diff --git a/.gitignore b/.gitignore index 10a953e72e57f8e66c0b8bb5973a4b735c0f88d0..578ed54a709f2f3f49182cbbc8f2c1ef978973c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +node_modules/ + # vim / vscode workspace config .vim .vscode diff --git a/client/package.json b/client/package.json index 65e3fbdf6815817995bf59d5f267c5a286898516..37832f4b9815423d7e6c8bd96157b8ca1af532dd 100644 --- a/client/package.json +++ b/client/package.json @@ -40,7 +40,7 @@ "scripts": { "start": "react-scripts start", "build": "react-scripts build", - "test": "react-scripts test" + "test": "react-scripts test --watchAll=false --passWithNoTests" }, "eslintConfig": { "extends": [ diff --git a/client/src/config.ts b/client/src/config.ts index cd15358f0b3a31f36a7a5d1dc4d395a6af9aec53..38c8d39c67e67d3c160d59ad6e398406abdeb632 100644 --- a/client/src/config.ts +++ b/client/src/config.ts @@ -1,3 +1,3 @@ -export const apiRoot = 'http://localhost:8000/v1'; +export const apiRoot = `${window.location.origin}/v1`; diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..6110cb38b7413587b3c6d04d21fed959b2030b1f --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "ryoko", + "version": "0.1.0", + "description": "Ryoko is a project planning tool build with developers in mind", + "repository": "https://gitlab.inf.unibz.it/Roland.Bernard/wie_202021_csbillero11.git/", + "author": "Roland Bernard <rolbernard@unibz.it>", + "license": "MIT", + "private": true, + "main": "server/build.js", + "scripts": { + "install": "cd server && yarn install --production=false && cd ../client && yarn install --production=false", + "build": "cd server && yarn build && cd ../client && yarn build", + "start": "cd server && node build/index.js" + }, + "keywords": [ ], + "dependencies": { }, + "engines": { + "node": "16.x" + } +} diff --git a/server/.gitignore b/server/.gitignore index 004eb80e075724168fc4ade631c5be02aec9c15b..9f6ae971042bb9601c55ac9c3ae07c7c303ee84e 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -14,3 +14,6 @@ *.db *.sqlite3 +# keys +/keys + diff --git a/server/package.json b/server/package.json index 59765578637096588f872e99df522f8a09980311..0037f532bf7823bfe6c3da460e98d31c9148646b 100644 --- a/server/package.json +++ b/server/package.json @@ -16,14 +16,14 @@ "express-fileupload": "^1.2.1", "jsonwebtoken": "^8.5.1", "knex": "^0.95.4", + "pg": "^8.6.0", "sharp": "^0.28.1", - "sqlite3": "^5.0.2", "uuid": "^8.3.2" }, "scripts": { "start": "nodemon src/index.ts", "build": "tsc --project .", - "test": "jest --watch --config ./jest.config.json" + "test": "jest --passWithNoTests --config ./jest.config.json" }, "devDependencies": { "@types/bcrypt": "^3.0.1", @@ -37,8 +37,10 @@ "@types/uuid": "^8.3.0", "jest": "^26.6.3", "nodemon": "^2.0.7", + "sqlite3": "^5.0.2", "ts-jest": "^26.5.4", "ts-node": "^9.1.1", + "tsc": "^2.0.3", "typescript": "^4.2.4" } } diff --git a/server/src/config.ts b/server/src/config.ts index e460c415edc4daad1f1b3f308f994e4ae91afd66..26fd98f447e9cad3fdbf8db5d0fd6c5346e72246 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -1,14 +1,16 @@ import { env } from 'process'; -export const port = 8000; +export const port = env.PORT ?? 8000; export const keys = { - private: '/etc/ssl/localcerts/cert.key', - public: '/etc/ssl/localcerts/cert.pem', + private: './keys/cert.key', + public: './keys/cert.pem', }; export const allowedOrigins = [ "*" ]; export const environment = (env.NODE_ENV ?? 'development') as ('development' | 'staging' | 'production'); +export const web_serve = '../client/build/'; + diff --git a/server/src/index.ts b/server/src/index.ts index cba9f525a5ed76cf2487dcea343e68a8b0a3e275..eade34b2b2cffa3c14560499a87455dde75be8a3 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -3,7 +3,7 @@ import express, { Request, Response, NextFunction } from 'express'; import { json as bodyJson } from 'body-parser'; import fileupload from 'express-fileupload'; -import { port } from './config'; +import { port, web_serve } from './config'; import { addDefaultHeaders } from './headers'; import v1 from './v1'; @@ -15,6 +15,9 @@ app.use(fileupload()); app.use('/v1', v1); +if (web_serve) { + app.use('/', express.static(web_serve)); +} app.use((_req, res) => { res.status(404).json({ @@ -30,7 +33,5 @@ app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => { }); }); -app.listen(port, () => { - console.log(`[server] Server is running at http://localhost:${port}`); -}); +app.listen(port); diff --git a/server/src/keys.ts b/server/src/keys.ts index 8b42a1bf87449300a306288f0574a39b1bba21d3..96e0edfb50554afd9e5333c1dfafd2dd19e66ee3 100644 --- a/server/src/keys.ts +++ b/server/src/keys.ts @@ -1,22 +1,31 @@ import { readFileBuffer } from './util'; +import { env } from 'process'; import { keys } from './config'; -let privateKey: Buffer; +let privateKey: string; -export async function getPrivateKey(): Promise<Buffer> { - if (!privateKey) { - privateKey = await readFileBuffer(keys.private); +export async function getPrivateKey(): Promise<string> { + if (env.JWT_PRIVATE_KEY) { + return env.JWT_PRIVATE_KEY; + } else { + if (!privateKey) { + privateKey = (await readFileBuffer(keys.private)).toString(); + } + return privateKey; } - return privateKey; } -let publicKey: Buffer; +let publicKey: string; -export async function getPublicKey(): Promise<Buffer> { - if (!publicKey) { - publicKey = await readFileBuffer(keys.public); +export async function getPublicKey(): Promise<string> { + if (env.JWT_PUBLIC_KEY) { + return env.JWT_PUBLIC_KEY; + } else { + if (!publicKey) { + publicKey = (await readFileBuffer(keys.public)).toString(); + } + return publicKey; } - return publicKey; } diff --git a/server/src/knexconfig.ts b/server/src/knexconfig.ts index eaefee815d6021077aa3bcf8e6fa181c6a77f71b..7f5a5030b168e6ef2bc5c57aac571a7073005cbe 100644 --- a/server/src/knexconfig.ts +++ b/server/src/knexconfig.ts @@ -1,40 +1,49 @@ +import { env } from 'process'; +import { join } from 'path'; +import { parse } from 'pg-connection-string'; + +const pgconfig: any = parse(env.DATABASE_URL ?? ''); + export default { development: { client: "sqlite3", connection: { - filename: "./dev.sqlite3" - } + filename: "./dev.sqlite3", + }, + migrations: { + tableName: "knex_migrations", + directory: join(__dirname, 'migrations'), + }, }, staging: { client: "postgresql", - connection: { - database: "my_db", - user: "username", - password: "password" - }, + connection: pgconfig, pool: { min: 2, - max: 10 + max: 10, }, migrations: { - tableName: "knex_migrations" - } + tableName: "knex_migrations", + directory: join(__dirname, 'migrations'), + }, }, production: { client: "postgresql", connection: { - database: "my_db", - user: "username", - password: "password" + ...pgconfig, + ssl: { + rejectUnauthorized: false, + } }, pool: { min: 2, - max: 10 + max: 10, }, migrations: { - tableName: "knex_migrations" - } + tableName: "knex_migrations", + directory: join(__dirname, 'migrations'), + }, } }; diff --git a/server/migrations/0000_initial.ts b/server/src/migrations/0000_initial.ts similarity index 100% rename from server/migrations/0000_initial.ts rename to server/src/migrations/0000_initial.ts index e247adb7cbe4cce5c1e6179e91908e97d631cbff..83bbfe6701f6aaa1bc79a7d4c3d0d8f6520c08d8 100644 --- a/server/migrations/0000_initial.ts +++ b/server/src/migrations/0000_initial.ts @@ -15,17 +15,17 @@ export async function up(database: Knex): Promise<void> { table.uuid('id').notNullable().primary(); table.text('name').notNullable(); }) + .createTable('roles', table => { + table.uuid('id').notNullable().primary(); + table.uuid('team_id').notNullable().references('teams.id'); + table.text('name').notNullable(); + }) .createTable('team_members', table => { table.uuid('user_id').notNullable().references('users.id'); table.uuid('team_id').notNullable().references('teams.id'); table.primary(['user_id', 'team_id']); table.uuid('role_id').notNullable().references('roles.id'); }) - .createTable('roles', table => { - table.uuid('id').notNullable().primary(); - table.uuid('team_id').notNullable().references('teams.id'); - table.text('name').notNullable(); - }) .createTable('projects', table => { table.uuid('id').notNullable().primary(); table.text('name').notNullable(); diff --git a/server/src/v1/user.ts b/server/src/v1/user.ts index 8d1db7eec2e0114ca7006d0762814a42de048fcc..e6c85ca5ab61272d5c94dfc96385dcebc0e23ba9 100644 --- a/server/src/v1/user.ts +++ b/server/src/v1/user.ts @@ -16,10 +16,10 @@ user.get('/name/:username', async (req, res) => { const name = req.params.username.trim().toLowerCase(); const user = await database('users') .select({ - id: 'id', - username: 'user_name', + id: 'users.id', + username: 'users.user_name', }) - .where({ username: name }); + .where({ 'users.user_name': name }); if (user.length >= 1) { res.status(200).json({ status: 'success', diff --git a/server/tsconfig.json b/server/tsconfig.json index 340c6162587908c9907869734f74cfc91f5d6e1a..199b23726ee6c84397f8a2b3ac7ca7c70fbab91a 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -11,7 +11,6 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "noEmit": true, "module": "commonjs", "rootDir": "src", "outDir": "build", diff --git a/server/yarn.lock b/server/yarn.lock index a9a0b168eec5d8fef27eb70a485634d3de757f02..ae7177ff917ff2717dbd39fa173305b53b907d2e 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -1150,6 +1150,11 @@ buffer-from@1.x, buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -3970,6 +3975,11 @@ package-json@^6.3.0: registry-url "^5.0.0" semver "^6.2.0" +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -4035,6 +4045,57 @@ pg-connection-string@2.4.0: resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.4.0.tgz#c979922eb47832999a204da5dbe1ebf2341b6a10" integrity sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ== +pg-connection-string@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" + integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.3.0.tgz#12d5c7f65ea18a6e99ca9811bd18129071e562fc" + integrity sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg== + +pg-protocol@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" + integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.6.0.tgz#e222296b0b079b280cce106ea991703335487db2" + integrity sha512-qNS9u61lqljTDFvmk/N66EeGq3n6Ujzj0FFyNMGQr6XuEv4tgNTXvJQTfJdcvGit5p5/DWPu+wj920hAJFI+QQ== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.5.0" + pg-pool "^3.3.0" + pg-protocol "^1.5.0" + pg-types "^2.1.0" + pgpass "1.x" + +pgpass@1.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.4.tgz#85eb93a83800b20f8057a2b029bf05abaf94ea9c" + integrity sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w== + dependencies: + split2 "^3.1.1" + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" @@ -4059,6 +4120,28 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + prebuild-install@^6.1.1: version "6.1.2" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.1.2.tgz#6ce5fc5978feba5d3cbffedca0682b136a0b5bff" @@ -4222,7 +4305,7 @@ readable-stream@^2.0.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.4.0: +readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -4698,6 +4781,13 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +split2@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -5093,6 +5183,11 @@ ts-node@^9.1.1: source-map-support "^0.5.17" yn "3.1.1" +tsc@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/tsc/-/tsc-2.0.3.tgz#037fe579e3bd67a5cbdaa604b43c6c1991b04bef" + integrity sha512-SN+9zBUtrpUcOpaUO7GjkEHgWtf22c7FKbKCA4e858eEM7Qz86rRDpgOU2lBIDf0fLCsEg65ms899UMUIB2+Ow== + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -5422,6 +5517,11 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000000000000000000000000000000000..fb57ccd13afbd082ad82051c2ffebef4840661ec --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +