diff --git a/packages/backend/db/migrations/20211005151457_create_users.ts b/packages/backend/db/migrations/20211005151457_create_users.ts new file mode 100644 index 00000000..d74dc3a5 --- /dev/null +++ b/packages/backend/db/migrations/20211005151457_create_users.ts @@ -0,0 +1,17 @@ +import { Knex } from "knex"; + +export async function up(knex: Knex): Promise { + return knex.schema.createTable('users', (table) => { + table.increments('id'); + table.string('email').unique().notNullable(); + table.string('password').notNullable(); + + table.timestamps(true, true); + }); + +} + +export async function down(knex: Knex): Promise { + return knex.schema.dropTable('users'); +} + diff --git a/packages/backend/package.json b/packages/backend/package.json index 10fc5dbc..0ff440c5 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -8,10 +8,12 @@ "start": "node dist/index.js", "test": "echo \"Error: run tests from root\" && exit 1", "db:create": "ts-node ./bin/database/create.ts", + "db:drop": "ts-node ./bin/database/drop.ts", "db:migration:create": "knex migrate:make", - "db:drop": "ts-node ./bin/database/drop.ts" + "db:migrate": "knex migrate:latest" }, "dependencies": { + "bcrypt": "^5.0.1", "cors": "^2.8.5", "debug": "~2.6.9", "dotenv": "^10.0.0", @@ -47,6 +49,7 @@ "url": "https://github.com/automatisch/automatisch/issues" }, "devDependencies": { + "@types/bcrypt": "^5.0.0", "@types/cors": "^2.8.12", "@types/express": "^4.17.13", "@types/http-errors": "^1.8.1", diff --git a/packages/backend/src/models/user.ts b/packages/backend/src/models/user.ts new file mode 100644 index 00000000..6e360a53 --- /dev/null +++ b/packages/backend/src/models/user.ts @@ -0,0 +1,40 @@ +import { Model, QueryContext, ModelOptions } from 'objection'; +import bcrypt from 'bcrypt'; + +class User extends Model { + id!: number + email!: string + password!: string + + static tableName = 'users'; + + static jsonSchema = { + type: 'object', + required: ['email', 'password'], + + properties: { + id: { type: 'integer' }, + email: { type: 'email', minLength: 1, maxLength: 255 }, + password: { type: 'string', minLength: 1, maxLength: 255 }, + } + } + + async generateHash() { + this.password = await bcrypt.hash(this.password, 10); + } + + async $beforeInsert(queryContext: QueryContext) { + await super.$beforeInsert(queryContext); + await this.generateHash() + } + + async $beforeUpdate(opt: ModelOptions, queryContext: QueryContext) { + await super.$beforeUpdate(opt, queryContext); + + if(this.password) { + await this.generateHash() + } + } +} + +export default User; diff --git a/yarn.lock b/yarn.lock index ad1d8fae..8524c6a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2374,6 +2374,21 @@ npmlog "^4.1.2" write-file-atomic "^3.0.3" +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz#2a0b32fcb416fb3f2250fd24cb2a81421a4f5950" + integrity sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA== + dependencies: + detect-libc "^1.0.3" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.1" + nopt "^5.0.0" + npmlog "^4.1.2" + rimraf "^3.0.2" + semver "^7.3.4" + tar "^6.1.0" + "@mui/core@5.0.0-alpha.49": version "5.0.0-alpha.49" resolved "https://registry.yarnpkg.com/@mui/core/-/core-5.0.0-alpha.49.tgz#e74d6ec7f83f85b55d48aa05ea6b7cefff88ce1b" @@ -2941,6 +2956,13 @@ dependencies: "@babel/types" "^7.3.0" +"@types/bcrypt@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-5.0.0.tgz#a835afa2882d165aff5690893db314eaa98b9f20" + integrity sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw== + dependencies: + "@types/node" "*" + "@types/body-parser@*": version "1.19.1" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c" @@ -4295,6 +4317,14 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bcrypt@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.1.tgz#f1a2c20f208e2ccdceea4433df0c8b2c54ecdf71" + integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + node-addon-api "^3.1.0" + before-after-hook@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" @@ -6016,6 +6046,11 @@ detect-indent@^6.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -9787,7 +9822,7 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0, make-dir@^3.0.2: +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -10350,6 +10385,11 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" +node-addon-api@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + node-fetch@^2.6.1: version "2.6.5" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd"