🏗️」 wip: refactor working

This commit is contained in:
2025-07-18 14:11:54 +02:00
parent 56f6164671
commit 1fb6d07d10
9 changed files with 397 additions and 133 deletions

View File

@ -4,6 +4,7 @@
# For launching the authentification api # For launching the authentification api
@auth $FASTIFY_LOG_LEVEL="info" $FASTIFY_PRETTY_LOGS="true": @auth $FASTIFY_LOG_LEVEL="info" $FASTIFY_PRETTY_LOGS="true":
fastify start src/api/auth/default.js fastify start src/api/auth/default.js
# For launching the user data api # For launching the user data api
@user $FASTIFY_LOG_LEVEL="info" $FASTIFY_PRETTY_LOGS="true": @user $FASTIFY_LOG_LEVEL="info" $FASTIFY_PRETTY_LOGS="true":
fastify start src/api/user/default.js fastify start src/api/user/default.js

View File

@ -1,3 +1,5 @@
name: ft_transcendence
services: services:
front: front:
container_name: transcendence-front container_name: transcendence-front
@ -5,7 +7,7 @@ services:
dockerfile: docker/front/Dockerfile dockerfile: docker/front/Dockerfile
context: .. context: ..
ports: ports:
- 8443:443 - ${OUT_PORT}:443
environment: environment:
SERVER_NAME: localhost SERVER_NAME: localhost
depends_on: depends_on:
@ -15,35 +17,48 @@ services:
condition: service_started condition: service_started
networks: networks:
- front - front
environment:
- TZ=Europe/Paris
restart: unless-stopped
user-api: user-api:
container_name: transcendence-api-user container_name: transcendence-api-user
build: build:
dockerfile: docker/api-base/Dockerfile dockerfile: docker/api-base/Dockerfile
context: .. context: ..
tags: volumes:
- api-base - db-user:/db
networks: networks:
- front - front
- back - back
environment: environment:
- TZ=Europe/Paris
- API_TARGET=user - API_TARGET=user
- JWT_SECRET=${JWT_SECRET}
restart: unless-stopped
auth-api: auth-api:
container_name: transcendence-api-auth container_name: transcendence-api-auth
build: build:
dockerfile: docker/api-base/Dockerfile dockerfile: docker/api-base/Dockerfile
context: .. context: ..
volumes:
- db-auth:/db
networks: networks:
- front - front
- back - back
environment: environment:
- TZ=Europe/Paris
- API_TARGET=auth - API_TARGET=auth
- JWT_SECRET=${JWT_SECRET}
restart: unless-stopped
networks: networks:
front: front:
external: false name: transcendence-front
name: front-backend
back: back:
external: false name: transcendence-back
name: trans-backend
volumes:
db-auth:
name: transcendence-api-auth-db
db-user:
name: transcendence-api-user-db

View File

@ -6,14 +6,15 @@
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"better-sqlite3": "^12.2.0", "better-sqlite3": "^12.2.0",
"fastify": "^5.4.0", "fastify": "^5.4.0",
"fastify-cli": "^7.4.0" "fastify-cli": "^7.4.0",
"google-auth-library": "^10.1.0"
}, },
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"typescript": "^5.8.3",
"tailwindcss": "^4.1.11",
"@tailwindcss/vite": "^4.1.11", "@tailwindcss/vite": "^4.1.11",
"pino-pretty": "^13.0.0", "pino-pretty": "^13.0.0",
"tailwindcss": "^4.1.11",
"typescript": "^5.8.3",
"vite": "^6.3.5" "vite": "^6.3.5"
} }
} }

180
pnpm-lock.yaml generated
View File

@ -29,6 +29,9 @@ importers:
fastify-cli: fastify-cli:
specifier: ^7.4.0 specifier: ^7.4.0
version: 7.4.0 version: 7.4.0
google-auth-library:
specifier: ^10.1.0
version: 10.1.0
devDependencies: devDependencies:
'@tailwindcss/vite': '@tailwindcss/vite':
specifier: ^4.1.11 specifier: ^4.1.11
@ -455,6 +458,10 @@ packages:
abstract-logging@2.0.1: abstract-logging@2.0.1:
resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
agent-base@7.1.4:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'}
ajv-formats@3.0.1: ajv-formats@3.0.1:
resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
peerDependencies: peerDependencies:
@ -491,6 +498,9 @@ packages:
resolution: {integrity: sha512-eGbYq2CT+tos1fBwLQ/tkBt9J5M3JEHjku4hbvQUePCckkvVf14xWj+1m7dGoK81M/fOjFT7yM9UMeKT/+vFLQ==} resolution: {integrity: sha512-eGbYq2CT+tos1fBwLQ/tkBt9J5M3JEHjku4hbvQUePCckkvVf14xWj+1m7dGoK81M/fOjFT7yM9UMeKT/+vFLQ==}
engines: {node: 20.x || 22.x || 23.x || 24.x} engines: {node: 20.x || 22.x || 23.x || 24.x}
bignumber.js@9.3.1:
resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==}
bindings@1.5.0: bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
@ -500,6 +510,9 @@ packages:
bn.js@4.12.2: bn.js@4.12.2:
resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==}
buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
buffer@5.7.1: buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
@ -538,9 +551,22 @@ packages:
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
engines: {node: '>=18'} engines: {node: '>=18'}
data-uri-to-buffer@4.0.1:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
dateformat@4.6.3: dateformat@4.6.3:
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
debug@4.4.1:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
decompress-response@6.0.0: decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -587,6 +613,9 @@ packages:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'} engines: {node: '>=6'}
extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
fast-copy@3.0.2: fast-copy@3.0.2:
resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==}
@ -647,6 +676,10 @@ packages:
picomatch: picomatch:
optional: true optional: true
fetch-blob@3.2.0:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
file-uri-to-path@1.0.0: file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
@ -658,6 +691,10 @@ packages:
resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
engines: {node: '>=6'} engines: {node: '>=6'}
formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
fs-constants@1.0.0: fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
@ -666,6 +703,14 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin] os: [darwin]
gaxios@7.1.1:
resolution: {integrity: sha512-Odju3uBUJyVCkW64nLD4wKLhbh93bh6vIg/ZIXkWiLPBrdgtc65+tls/qml+un3pr6JqYVFDZbbmLDQT68rTOQ==}
engines: {node: '>=18'}
gcp-metadata@7.0.1:
resolution: {integrity: sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==}
engines: {node: '>=18'}
generify@4.2.0: generify@4.2.0:
resolution: {integrity: sha512-b4cVhbPfbgbCZtK0dcUc1lASitXGEAIqukV5DDAyWm25fomWnV+C+a1yXvqikcRZXHN2j0pSDyj3cTfzq8pC7Q==} resolution: {integrity: sha512-b4cVhbPfbgbCZtK0dcUc1lASitXGEAIqukV5DDAyWm25fomWnV+C+a1yXvqikcRZXHN2j0pSDyj3cTfzq8pC7Q==}
hasBin: true hasBin: true
@ -673,9 +718,21 @@ packages:
github-from-package@0.0.0: github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
google-auth-library@10.1.0:
resolution: {integrity: sha512-GspVjZj1RbyRWpQ9FbAXMKjFGzZwDKnUHi66JJ+tcjcu5/xYAP1pdlWotCuIkMwjfVsxxDvsGZXGLzRt72D0sQ==}
engines: {node: '>=18'}
google-logging-utils@1.1.1:
resolution: {integrity: sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==}
engines: {node: '>=14'}
graceful-fs@4.2.11: graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
gtoken@8.0.0:
resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==}
engines: {node: '>=18'}
has-flag@4.0.0: has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -683,6 +740,10 @@ packages:
help-me@5.0.0: help-me@5.0.0:
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
https-proxy-agent@7.0.6:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
ieee754@1.2.1: ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@ -713,12 +774,21 @@ packages:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'} engines: {node: '>=10'}
json-bigint@1.0.0:
resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
json-schema-ref-resolver@2.0.1: json-schema-ref-resolver@2.0.1:
resolution: {integrity: sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q==} resolution: {integrity: sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q==}
json-schema-traverse@1.0.0: json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
jwa@2.0.1:
resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==}
jws@4.0.0:
resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==}
light-my-request@6.6.0: light-my-request@6.6.0:
resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==}
@ -825,6 +895,9 @@ packages:
mnemonist@0.40.3: mnemonist@0.40.3:
resolution: {integrity: sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==} resolution: {integrity: sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
nanoid@3.3.11: nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@ -841,6 +914,15 @@ packages:
resolution: {integrity: sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg==} resolution: {integrity: sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg==}
engines: {node: ^18 || ^20 || >= 21} engines: {node: ^18 || ^20 || >= 21}
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
deprecated: Use your platform's native DOMException instead
node-fetch@3.3.2:
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
node-gyp-build@4.8.4: node-gyp-build@4.8.4:
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
hasBin: true hasBin: true
@ -1108,6 +1190,10 @@ packages:
walker@1.0.8: walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
wrappy@1.0.2: wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@ -1406,6 +1492,8 @@ snapshots:
abstract-logging@2.0.1: {} abstract-logging@2.0.1: {}
agent-base@7.1.4: {}
ajv-formats@3.0.1(ajv@8.17.1): ajv-formats@3.0.1(ajv@8.17.1):
optionalDependencies: optionalDependencies:
ajv: 8.17.1 ajv: 8.17.1
@ -1447,6 +1535,8 @@ snapshots:
bindings: 1.5.0 bindings: 1.5.0
prebuild-install: 7.1.3 prebuild-install: 7.1.3
bignumber.js@9.3.1: {}
bindings@1.5.0: bindings@1.5.0:
dependencies: dependencies:
file-uri-to-path: 1.0.0 file-uri-to-path: 1.0.0
@ -1459,6 +1549,8 @@ snapshots:
bn.js@4.12.2: {} bn.js@4.12.2: {}
buffer-equal-constant-time@1.0.1: {}
buffer@5.7.1: buffer@5.7.1:
dependencies: dependencies:
base64-js: 1.5.1 base64-js: 1.5.1
@ -1491,8 +1583,14 @@ snapshots:
cookie@1.0.2: {} cookie@1.0.2: {}
data-uri-to-buffer@4.0.1: {}
dateformat@4.6.3: {} dateformat@4.6.3: {}
debug@4.4.1:
dependencies:
ms: 2.1.3
decompress-response@6.0.0: decompress-response@6.0.0:
dependencies: dependencies:
mimic-response: 3.1.0 mimic-response: 3.1.0
@ -1557,6 +1655,8 @@ snapshots:
expand-template@2.0.3: {} expand-template@2.0.3: {}
extend@3.0.2: {}
fast-copy@3.0.2: {} fast-copy@3.0.2: {}
fast-decode-uri-component@1.0.1: {} fast-decode-uri-component@1.0.1: {}
@ -1650,6 +1750,11 @@ snapshots:
optionalDependencies: optionalDependencies:
picomatch: 4.0.2 picomatch: 4.0.2
fetch-blob@3.2.0:
dependencies:
node-domexception: 1.0.0
web-streams-polyfill: 3.3.3
file-uri-to-path@1.0.0: {} file-uri-to-path@1.0.0: {}
find-my-way@9.3.0: find-my-way@9.3.0:
@ -1662,11 +1767,31 @@ snapshots:
dependencies: dependencies:
locate-path: 3.0.0 locate-path: 3.0.0
formdata-polyfill@4.0.10:
dependencies:
fetch-blob: 3.2.0
fs-constants@1.0.0: {} fs-constants@1.0.0: {}
fsevents@2.3.3: fsevents@2.3.3:
optional: true optional: true
gaxios@7.1.1:
dependencies:
extend: 3.0.2
https-proxy-agent: 7.0.6
node-fetch: 3.3.2
transitivePeerDependencies:
- supports-color
gcp-metadata@7.0.1:
dependencies:
gaxios: 7.1.1
google-logging-utils: 1.1.1
json-bigint: 1.0.0
transitivePeerDependencies:
- supports-color
generify@4.2.0: generify@4.2.0:
dependencies: dependencies:
isbinaryfile: 4.0.10 isbinaryfile: 4.0.10
@ -1676,12 +1801,40 @@ snapshots:
github-from-package@0.0.0: {} github-from-package@0.0.0: {}
google-auth-library@10.1.0:
dependencies:
base64-js: 1.5.1
ecdsa-sig-formatter: 1.0.11
gaxios: 7.1.1
gcp-metadata: 7.0.1
google-logging-utils: 1.1.1
gtoken: 8.0.0
jws: 4.0.0
transitivePeerDependencies:
- supports-color
google-logging-utils@1.1.1: {}
graceful-fs@4.2.11: {} graceful-fs@4.2.11: {}
gtoken@8.0.0:
dependencies:
gaxios: 7.1.1
jws: 4.0.0
transitivePeerDependencies:
- supports-color
has-flag@4.0.0: {} has-flag@4.0.0: {}
help-me@5.0.0: {} help-me@5.0.0: {}
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.4
debug: 4.4.1
transitivePeerDependencies:
- supports-color
ieee754@1.2.1: {} ieee754@1.2.1: {}
inherits@2.0.4: {} inherits@2.0.4: {}
@ -1698,12 +1851,27 @@ snapshots:
joycon@3.1.1: {} joycon@3.1.1: {}
json-bigint@1.0.0:
dependencies:
bignumber.js: 9.3.1
json-schema-ref-resolver@2.0.1: json-schema-ref-resolver@2.0.1:
dependencies: dependencies:
dequal: 2.0.3 dequal: 2.0.3
json-schema-traverse@1.0.0: {} json-schema-traverse@1.0.0: {}
jwa@2.0.1:
dependencies:
buffer-equal-constant-time: 1.0.1
ecdsa-sig-formatter: 1.0.11
safe-buffer: 5.2.1
jws@4.0.0:
dependencies:
jwa: 2.0.1
safe-buffer: 5.2.1
light-my-request@6.6.0: light-my-request@6.6.0:
dependencies: dependencies:
cookie: 1.0.2 cookie: 1.0.2
@ -1788,6 +1956,8 @@ snapshots:
dependencies: dependencies:
obliterator: 2.0.5 obliterator: 2.0.5
ms@2.1.3: {}
nanoid@3.3.11: {} nanoid@3.3.11: {}
napi-build-utils@2.0.0: {} napi-build-utils@2.0.0: {}
@ -1798,6 +1968,14 @@ snapshots:
node-addon-api@8.4.0: {} node-addon-api@8.4.0: {}
node-domexception@1.0.0: {}
node-fetch@3.3.2:
dependencies:
data-uri-to-buffer: 4.0.1
fetch-blob: 3.2.0
formdata-polyfill: 4.0.10
node-gyp-build@4.8.4: {} node-gyp-build@4.8.4: {}
obliterator@2.0.5: {} obliterator@2.0.5: {}
@ -2073,6 +2251,8 @@ snapshots:
dependencies: dependencies:
makeerror: 1.0.12 makeerror: 1.0.12
web-streams-polyfill@3.3.3: {}
wrappy@1.0.2: {} wrappy@1.0.2: {}
xtend@4.0.2: {} xtend@4.0.2: {}

View File

@ -1,55 +1,13 @@
import fastifyJWT from '@fastify/jwt'; import fastifyJWT from '@fastify/jwt';
import fastifyCookie from '@fastify/cookie'; import fastifyCookie from '@fastify/cookie';
import Database from 'better-sqlite3';
import bcrypt from 'bcrypt';
const RESERVED_USERNAMES = ['admin']; import { register } from './register.js';
var env = process.env.NODE_ENV || 'development'; import { login } from './login.js';
import authDB from '../../utils/authDB.js'
const saltRounds = 10; const saltRounds = 10;
let database;
if (env === 'development') { authDB.prepareDB();
database = new Database(":memory:", { verbose: console.log });
} else {
var dbPath = process.env.DB_PATH || '/db/db.sqlite'
database = new Database(dbPath);
}
/**
* @description Can be used to prepare the database
*/
function prepareDB() {
database.exec(`
CREATE TABLE credentials (
username TEXT PRIMARY KEY,
passwordHash TEXT
) STRICT
`);
}
prepareDB()
const userCheck = database.prepare('SELECT EXISTS (SELECT 1 FROM credentials WHERE username = ?);');
const passwordQuery = database.prepare('SELECT passwordHash FROM credentials WHERE username = ?;');
const userAdd = database.prepare('INSERT INTO credentials (username, passwordHash) VALUES (?, ?)');
/**
* @description Can be used to check is a user exists in the database
* @param {string} name
*
* @returns {boolean}
*/
function checkUser(name) {
const result = userCheck.get(name);
const key = Object.keys(result)[0];
return result[key] === 1;
}
function isValidString(value) {
return typeof value === 'string' && value.trim() !== '';
}
/** /**
* @param {import('fastify').FastifyInstance} fastify * @param {import('fastify').FastifyInstance} fastify
@ -67,6 +25,19 @@ export default async function(fastify, options) {
}); });
fastify.register(fastifyCookie); fastify.register(fastifyCookie);
fastify.get('/me', async (request, reply) => {
try {
const token = request.cookies.token;
const decoded = await fastify.jwt.verify(token);
return { user: decoded.user };
} catch {
return reply.code(401).send({ error: 'Unauthorized' });
}
});
// GOOGLE sign in
fastify.post('/login', { fastify.post('/login', {
schema: { schema: {
body: { body: {
@ -78,44 +49,7 @@ export default async function(fastify, options) {
} }
} }
} }
}, async (request, reply) => { }, async (request, reply) => { return login(request, reply, fastify); });
try {
/** @type {{ user: string, password: string }} */
const { user, password } = request.body;
if (!checkUser(user) || user === 'admin') {
return reply.code(400).send({ error: "User does not exist" });
}
const query = passwordQuery.get(user);
const hash = query?.passwordHash;
if (!hash) {
return reply.code(500).send({ error: "No password was found" });
}
const compare = await bcrypt.compare(password, hash);
if (!compare) {
return reply.code(401).send({ error: "Incorrect password" });
}
const token = fastify.jwt.sign({ user });
return reply
.setCookie('token', token, {
httpOnly: true,
path: '/',
secure: env !== 'development',
sameSite: 'lax',
})
.code(200)
.send({ msg: "Login successful" });
} catch (err) {
fastify.log.error(err);
return reply.code(500).send({ error: "Internal server error" });
}
});
fastify.post('/register', { fastify.post('/register', {
schema: { schema: {
@ -128,41 +62,5 @@ export default async function(fastify, options) {
} }
} }
} }
}, async (request, reply) => { }, async (request, reply) => { return register(request, reply, saltRounds, fastify); });
try {
/** @type {{ user: string, password: string }} */
const { user, password } = request.body;
if (RESERVED_USERNAMES.includes(user)) {
return reply.code(400).send({ error: 'Reserved username' });
}
if (!isValidString(user) || !isValidString(password)) {
return reply.code(400).send({ error: 'Invalid username or password' });
} else if (checkUser(user) === true) {
return reply.code(400).send({ error: "User already exist" });
} else if (password.length <= 8) {
return reply.code(400).send({ error: "Password too short" });
} else if (password.length > 64) {
return reply.code(400).send({ error: "Password too long" });
}
const hash = await bcrypt.hash(password, saltRounds);
userAdd.run(user, hash);
return reply.code(200).send({ msg: 'Register successfuly' });
} catch (err) {
fastify.log.error(err);
return reply.code(500).send({ error: "Internal server error" });
}
});
fastify.get('/me', async (request, reply) => {
try {
const token = request.cookies.token;
const decoded = await fastify.jwt.verify(token);
return { user: decoded.user };
} catch {
return reply.code(401).send({ error: 'Unauthorized' });
}
});
} }

53
src/api/auth/login.js Normal file
View File

@ -0,0 +1,53 @@
import bcrypt from 'bcrypt';
import { checkUser } from '../../utils/authUtils.js';
import authDB from '../../utils/authDB.js';
var env = process.env.NODE_ENV || 'development';
/**
* @async
* @param {import("fastify").FastifyRequest} request
* @param {import("fastify").FastifyReply} reply
* @param {import("fastify").FastifyInstance} fastify
*
* @returns {import('fastify').FastifyReply}
*/
export async function login(request, reply, fastify) {
try {
/** @type {{ user: string, password: string }} */
const { user, password } = request.body;
if (!checkUser(user) || user === 'admin') {
return reply.code(400).send({ error: "User does not exist" });
}
const query = authDB.passwordQuery.get(user);
const hash = query?.passwordHash;
if (!hash) {
return reply.code(500).send({ error: "No password was found" });
}
const compare = await bcrypt.compare(password, hash);
if (!compare) {
return reply.code(401).send({ error: "Incorrect password" });
}
const token = fastify.jwt.sign({ user });
return reply
.setCookie('token', token, {
httpOnly: true,
path: '/',
secure: env !== 'development',
sameSite: 'lax',
})
.code(200)
.send({ msg: "Login successful" });
} catch (err) {
fastify.log.error(err);
return reply.code(500).send({ error: "Internal server error" });
}
}

54
src/api/auth/register.js Normal file
View File

@ -0,0 +1,54 @@
import bcrypt from 'bcrypt';
import { isValidString, checkUser } from '../../utils/authUtils.js';
import authDB from '../../utils/authDB.js';
var env = process.env.NODE_ENV || 'development';
/**
* @async
* @param {import("fastify").FastifyRequest} request
* @param {import("fastify").FastifyReply} reply
* @param {number} saltRounds
* @param {import("fastify").FastifyInstance} fastify
*
* @returns {import('fastify').FastifyReply}
*/
export async function register(request, reply, saltRounds, fastify) {
try {
/** @type {{ user: string, password: string }} */
const { user, password } = request.body;
if (authDB.RESERVED_USERNAMES.includes(user)) {
return reply.code(400).send({ error: 'Reserved username' });
}
if (!isValidString(user) || !isValidString(password)) {
return reply.code(400).send({ error: 'Invalid username or password' });
} else if (checkUser(user) === true) {
return reply.code(400).send({ error: "User already exist" });
} else if (password.length <= 8) {
return reply.code(400).send({ error: "Password too short" });
} else if (password.length > 64) {
return reply.code(400).send({ error: "Password too long" });
}
const hash = await bcrypt.hash(password, saltRounds);
authDB.userAdd.run(user, hash);
const token = fastify.jwt.sign({ user });
return reply
.setCookie('token', token, {
httpOnly: true,
path: '/',
secure: env !== 'development',
sameSite: 'lax',
})
.code(200)
.send({ msg: 'Register successfuly' });
} catch (err) {
fastify.log.error(err);
return reply.code(500).send({ error: "Internal server error" });
}
}

39
src/utils/authDB.js Normal file
View File

@ -0,0 +1,39 @@
import Database from 'better-sqlite3';
var env = process.env.NODE_ENV || 'development';
let database;
const RESERVED_USERNAMES = ['admin'];
let userCheck, passwordQuery, userAdd;
if (!env || env === 'development') {
database = new Database(":memory:", { verbose: console.log });
} else {
var dbPath = process.env.DB_PATH || '/db/db.sqlite';
database = new Database(dbPath);
}
/**
* @description Can be used to prepare the database
*/
function prepareDB() {
database.exec(`
CREATE TABLE IF NOT EXISTS credentials (
username TEXT PRIMARY KEY,
passwordHash TEXT
) STRICT
`);
userCheck = database.prepare('SELECT EXISTS (SELECT 1 FROM credentials WHERE username = ?);');
passwordQuery = database.prepare('SELECT passwordHash FROM credentials WHERE username = ?;');
userAdd = database.prepare('INSERT INTO credentials (username, passwordHash) VALUES (?, ?)');
}
const authDB = {
prepareDB,
get userCheck() { return userCheck; },
get userAdd() { return userAdd; },
get passwordQuery() { return passwordQuery; },
RESERVED_USERNAMES
};
export default authDB;

23
src/utils/authUtils.js Normal file
View File

@ -0,0 +1,23 @@
import authDB from './authDB.js';
/**
* @param {string} value
*
* @returns {boolean}
*/
export function isValidString(value) {
return typeof value === 'string' && value.trim() !== '';
}
/**
* @param {string} name
* @param {import('better-sqlite3').Statement} userCheck
*
* @returns {boolean}
*/
export function checkUser(name, userCheck) {
const result = authDB.userCheck.get(name);
const key = Object.keys(result)[0];
return result[key] === 1;
}