Skip to content
This repository was archived by the owner on Jan 1, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a30490e
Refactor register_user procedure and update schema for username valid…
Jun 9, 2025
6442189
Change parameter types from VARCHAR to TEXT in authenticate_user and …
Jun 9, 2025
2d5f800
Fix parameter order in register_user procedure for consistency
Jun 9, 2025
a7fb957
Add is_user_available function to check user availability by username…
Jun 9, 2025
521034d
Update register_user procedure to use language_id directly and enhanc…
Jun 9, 2025
5480e8b
Refactor register_user procedure to remove exception handling and sim…
Jun 9, 2025
23f9789
Enhance task configuration by adding Docker-related tasks for buildin…
Jun 11, 2025
0a608a2
Update password_hash constraint to enforce Argon2id hash format for i…
Jun 11, 2025
789dcb1
Refactor is_user_available function to is_email_available for clarity…
Jun 11, 2025
667945f
Reintroduce is_email_available function for email availability checks…
Jun 11, 2025
2913018
Refactor user authentication and registration processes; remove obsol…
Jun 12, 2025
51f8bd3
Enhance user registration and authentication: add OTP secret handling…
Jun 12, 2025
db5f2b8
Fix bump type detection for breaking changes in version suggestion wo…
Jun 12, 2025
6f22a48
Fix formatting in tasks.json by ensuring consistent problemMatcher st…
Jun 12, 2025
d064a68
Enhance SQL function definitions and schema: standardize authenticati…
Jun 12, 2025
5b9ddf9
Enhance Super-Linter configuration: enable JSON fixing to improve cod…
Jun 12, 2025
bd51baf
Enhance Super-Linter configuration: enable JSONC formatting for impro…
Jun 13, 2025
18ec003
Fix Super-Linter configuration: enable JSON and JSONC formatting opti…
Jun 13, 2025
d65070c
Super-Linter: Fix linting issues
Vianpyro Jun 13, 2025
13da952
Refactor unit tests workflow: streamline SQL file flattening and load…
Jun 13, 2025
d24b4f3
Refactor SQL functions: clean up syntax and remove unused function
Jun 13, 2025
570fdb5
Update devcontainer and tasks configuration: specify database directo…
Jun 13, 2025
10235fe
Super-Linter: Fix linting issues
Vianpyro Jun 13, 2025
058fc0d
Add token_type column to user_sessions and create procedures for sess…
Jun 17, 2025
22387af
Enhance user session management: add procedures for expiring tokens, …
Jun 19, 2025
b679057
Refactor user session procedures: update create_user_session_token an…
Jun 19, 2025
2714490
Remove email_verifications table and related trigger; update README a…
Jun 19, 2025
b3c0a4d
Merge branch 'main' into feature/secure_registration_add_login
Jun 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
},
"postCreateCommand": "initdb -D $PGDATA && pg_ctl -D $PGDATA -o '-k /run/postgresql' -l /tmp/pg.log start && createdb chocomax && pg_ctl -D $PGDATA stop",
"postStartCommand": "pg_ctl -D $PGDATA -o '-k /run/postgresql' -l /tmp/pg.log start",
"postAttachCommand": "sqlfluff fix database/ -v",
"remoteUser": "vscode"
}
2 changes: 1 addition & 1 deletion .github/workflows/suggest-version-bump.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
BUMP="patch"
echo "$LABELS" | grep -q 'type: feature' && BUMP="minor"
echo "$LABELS" | grep -q 'type: security' && BUMP="minor"
echo "$LABELS" | grep -q 'type: breaking' && BUMP="major"
echo "$LABELS" | grep -q 'special: breaking change' && BUMP="major"
echo "bump=$BUMP" >> "$GITHUB_OUTPUT"

- name: Get latest tag
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/super-linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ jobs:
uses: super-linter/super-linter/slim@v7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VALIDATE_ALL_CODEBASE: false
FILTER_REGEX_EXCLUDE: '(.github/pull_request_template.md|.github/ISSUE_TEMPLATE/*.md)'
DISABLE_ERRORS: true

fix-lint:
name: Fix Lint
Expand All @@ -46,6 +45,7 @@ jobs:
VALIDATE_ALL_CODEBASE: false
FILTER_REGEX_EXCLUDE: '(.github/pull_request_template.md|.github/ISSUE_TEMPLATE/*.md)'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FIX_JSON: true
FIX_JSON_PRETTIER: true
FIX_MARKDOWN: true
FIX_MARKDOWN_PRETTIER: true
Expand All @@ -61,6 +61,6 @@ jobs:
uses: stefanzweifel/git-auto-commit-action@v5
with:
branch: ${{ github.event.pull_request.head.ref }}
commit_message: 'chore: fix linting issues'
commit_message: 'Super-Linter: Fix linting issues'
commit_user_name: super-linter
commit_user_email: [email protected]
15 changes: 6 additions & 9 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,14 @@ jobs:
run: |
sudo -u "$PG_USER" psql -p "$PGPORT" -d "$PG_DATABASE" -c "CREATE EXTENSION IF NOT EXISTS pgtap;"

- name: Flatten and load schema SQL files
- name: Flatten SQL files
run: |
mkdir flattened-sql
find database -type f -name "*.sql" ! -name "*.session.sql" ! -name "*.test.sql" | while read -r file; do
clean_path="${file#./}"
new_name="${clean_path//\//_}"
cp "$file" "flattened-sql/$new_name"
echo "✅ Copied: $file → flattened-sql/$new_name"
done
chmod +x scripts/flatten-sql.sh
./scripts/flatten-sql.sh database flattened-sql

find flattened-sql -maxdepth 1 -name "*.sql" | while read -r file; do
- name: Load schema and seed data
run: |
find flattened-sql -maxdepth 1 -name "*.sql" | sort | while read -r file; do
echo "➡️ Running $file..."
sudo -u postgres psql -p "$PGPORT" -d "$PG_DATABASE" -f "$file"
done
Expand Down
9 changes: 3 additions & 6 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,6 @@
},
"presentation": {
"close": true
},
"runOptions": {
"runOn": "default"
}
},
{
Expand All @@ -125,7 +122,7 @@
"panel": "shared",
"close": true
},
"problemMatcher": [],
"problemMatcher": []
},
{
"label": "Run Docker Container",
Expand All @@ -135,7 +132,7 @@
"panel": "shared",
"close": true
},
"problemMatcher": [],
"problemMatcher": []
},
{
"label": "Remove Docker Container",
Expand All @@ -145,7 +142,7 @@
"panel": "shared",
"close": true
},
"problemMatcher": [],
"problemMatcher": []
},
{
"label": "Reset Docker Container",
Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ The database schema consists of the following tables:
5. **category_translations**: Contains translated names and descriptions for product categories.
6. **contact_messages**: Stores messages sent through the contact form by users or visitors.
7. **discount_codes**: Defines promotional discount codes with rules and usage limits.
8. **email_verifications**: Manages email verification tokens and statuses for user accounts.
9. **feedback**: Allows users to rate and comment on products they've purchased.
10. **login_attempts**: Records login attempts with metadata like IP, user agent, and success flag.
11. **loyalty_program**: Defines promotions such as "buy X get Y" for specific products.
12. **metrics_events**: Stores anonymous event logs for analytics purposes.
13. **moderation_actions**: Logs actions taken to moderate users, products, or comments.
14. **order_delivery_info**: Stores delivery-related information such as address and delivery agent.
15. **order_items**: Contains product variant items included in each order.
16. **order_status_history**: Tracks the status changes of orders over time.
17. **order_timestamps**: Keeps timestamps for different stages in the order lifecycle.
18. **orders**: Main order records with price, status, and delivery type.
19. **password_resets**: Stores reset tokens for users to change their passwords securely.
8. **feedback**: Allows users to rate and comment on products they've purchased.
9. **login_attempts**: Records login attempts with metadata like IP, user agent, and success flag.
10. **loyalty_program**: Defines promotions such as "buy X get Y" for specific products.
11. **metrics_events**: Stores anonymous event logs for analytics purposes.
12. **moderation_actions**: Logs actions taken to moderate users, products, or comments.
13. **order_delivery_info**: Stores delivery-related information such as address and delivery agent.
14. **order_items**: Contains product variant items included in each order.
15. **order_status_history**: Tracks the status changes of orders over time.
16. **order_timestamps**: Keeps timestamps for different stages in the order lifecycle.
17. **orders**: Main order records with price, status, and delivery type.
18. **password_resets**: Stores reset tokens for users to change their passwords securely.
19. **pending_users**: Manages email verification tokens and for new user.
20. **product_categories**: Defines categories to group products (e.g., Chocolate, Gifts).
21. **product_comments**: Stores user comments on products, optionally moderated.
22. **product_images**: Manages images associated with products and their variants.
Expand Down
27 changes: 0 additions & 27 deletions database/functions/authenticate_user.sql

This file was deleted.

8 changes: 0 additions & 8 deletions database/functions/disable_2fa.sql

This file was deleted.

10 changes: 10 additions & 0 deletions database/functions/get_password_hash_by_email_hash.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Returns the password hash for a given email hash (for API-side verification)
CREATE OR REPLACE FUNCTION get_password_hash_by_email_hash(
p_email_hash TEXT
)
RETURNS TEXT AS $$
SELECT password_hash
FROM users
WHERE email_hash = p_email_hash
LIMIT 1;
$$ LANGUAGE sql;
11 changes: 11 additions & 0 deletions database/functions/get_used_discriminators.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE OR REPLACE FUNCTION get_used_discriminators(
p_username TEXT
)
RETURNS SETOF SMALLINT AS $$
BEGIN
RETURN QUERY
SELECT discriminator
FROM users
WHERE username = p_username;
END;
$$ LANGUAGE plpgsql;
13 changes: 13 additions & 0 deletions database/functions/get_user_2fa_methods_by_email_hash.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- Returns the 2FA secret and authentication method for a given email hash and authentication method (e.g., TOTP)
CREATE OR REPLACE FUNCTION get_user_2fa_methods_by_email_hash(
p_email_hash TEXT
)
RETURNS TABLE (
authentication_method AUTHENTICATION_METHOD,
is_preferred BOOLEAN
) AS $$
SELECT authentication_method, is_preferred
FROM user_authentication_methods
WHERE user_id = (SELECT user_id FROM users WHERE email_hash = p_email_hash)
AND is_enabled = TRUE;
$$ LANGUAGE sql STABLE;
8 changes: 7 additions & 1 deletion database/functions/get_user_2fa_secret.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
-- Get the user's authentication methods secret
CREATE OR REPLACE FUNCTION get_user_authentication_method_secret(p_user_id UUID) RETURNS TABLE (method TEXT, secret TEXT) AS $$
CREATE OR REPLACE FUNCTION get_user_authentication_method_secret(
p_user_id UUID
)
RETURNS TABLE (
method TEXT,
secret TEXT
) AS $$
BEGIN
RETURN QUERY
SELECT authentication_method, user_authentication_method_secret
Expand Down
16 changes: 16 additions & 0 deletions database/functions/get_user_2fa_secret_by_email_hash.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- Returns the 2FA secret and authentication method for a given email hash and authentication method (e.g., TOTP)
CREATE OR REPLACE FUNCTION get_user_2fa_secret_by_email_hash(
p_email_hash TEXT,
p_authentication_method AUTHENTICATION_METHOD
)
RETURNS TABLE (
authentication_secret TEXT,
authentication_method AUTHENTICATION_METHOD
) AS $$
SELECT user_authentication_method_secret AS authentication_secret, authentication_method
FROM user_authentication_methods
WHERE user_id = (SELECT user_id FROM users WHERE email_hash = p_email_hash)
AND authentication_method = p_authentication_method
AND is_enabled = TRUE
LIMIT 1;
$$ LANGUAGE sql STABLE;
31 changes: 31 additions & 0 deletions database/functions/get_user_info_by_email_hash.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- Returns all non-sensitive user data for a given email hash

CREATE OR REPLACE FUNCTION get_user_info_by_email_hash(p_email_hash TEXT)
RETURNS TABLE (
user_id UUID,
username TEXT,
discriminator SMALLINT,
email_encrypted TEXT,
phone_encrypted TEXT,
language_id INTEGER,
display_role TEXT,
created_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ,
last_login_at TIMESTAMPTZ,
deleted_at TIMESTAMPTZ
) AS $$
SELECT
user_id,
username,
discriminator,
email_encrypted,
phone_encrypted,
language_id,
display_role,
created_at,
updated_at,
last_login_at,
deleted_at
FROM users
WHERE email_hash = p_email_hash;
$$ LANGUAGE sql STABLE;
23 changes: 19 additions & 4 deletions database/functions/is_email_available.sql
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
CREATE OR REPLACE FUNCTION is_email_available(
p_email_hash TEXT
p_verification_token TEXT
)
RETURNS BOOLEAN AS $$
SELECT NOT EXISTS (
SELECT 1 FROM users WHERE email_hash = p_email_hash
DECLARE
v_email_hash TEXT;
BEGIN
-- Retrieve the email_hash from pending_users using the verification_token
SELECT email_hash INTO v_email_hash
FROM pending_users
WHERE verification_token = p_verification_token;

-- If not found, return false
IF v_email_hash IS NULL THEN
RETURN FALSE;
END IF;

-- Check if email_hash exists in users
RETURN NOT EXISTS (
SELECT 1 FROM users WHERE email_hash = v_email_hash
);
$$ LANGUAGE sql;
END;
$$ LANGUAGE plpgsql;
29 changes: 29 additions & 0 deletions database/functions/is_verification_token_valid.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
CREATE OR REPLACE FUNCTION is_verification_token_valid(p_verification_token TEXT)
RETURNS BOOLEAN AS $$
DECLARE
v_email_hash TEXT;
BEGIN
-- Get email_hash of the token
SELECT email_hash INTO v_email_hash
FROM pending_users
WHERE verification_token = p_verification_token;

IF v_email_hash IS NULL THEN
RETURN FALSE;
END IF;

-- Check that this token is the most recent and not expired
RETURN EXISTS (
SELECT 1
FROM pending_users
WHERE email_hash = v_email_hash
AND verification_token = p_verification_token
AND created_at = (
SELECT MAX(created_at)
FROM pending_users
WHERE email_hash = v_email_hash
)
AND created_at >= NOW() - INTERVAL '24 hours'
);
END;
$$ LANGUAGE plpgsql STABLE;
11 changes: 11 additions & 0 deletions database/functions/update_last_login_at.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE OR REPLACE FUNCTION update_last_login_at()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.token_type = 'access' THEN
UPDATE users
SET last_login_at = current_timestamp
WHERE user_id = NEW.user_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
7 changes: 7 additions & 0 deletions database/functions/update_updated_at.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at := current_timestamp;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
18 changes: 18 additions & 0 deletions database/procedures/create_pending_user.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
CREATE OR REPLACE PROCEDURE create_pending_user(
p_email_encrypted TEXT,
p_email_hash TEXT,
p_verification_token TEXT
)
AS $$
BEGIN
INSERT INTO pending_users (
email_encrypted,
email_hash,
verification_token
) VALUES (
p_email_encrypted,
p_email_hash,
p_verification_token
);
END;
$$ LANGUAGE plpgsql;
Loading