diff --git a/docker-compose.yml b/docker-compose.yml index da905bdfdc13a6af67a7c4bc91f605cfdb441e08..c32a3b016120cb37f7fda9f1f911009c73a7e9f1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,15 +33,15 @@ services: - "5432:5432" labels: tech.jetsam.environment: 'staging' - graphql-engine: - image: hasura/graphql-engine:v2.4.0-beta.1 - restart: on-failure - ports: - - "15432:8080" - depends_on: - - "postgres" - env_file: - - hasura/.env +# graphql-engine: +# image: hasura/graphql-engine:v2.4.0-beta.1 +# restart: on-failure +# ports: +# - "15432:8080" +# depends_on: +# - "postgres" +# env_file: +# - hasura/.env # hsaura: # image: hasura/graphql-engine:v1.3.3 # ports: diff --git a/package-lock.json b/package-lock.json index 45c5bad01f0569b5dfa8fd4a69397609a704be96..df92de0248ab19072cb5998f27bea3c99e0dae5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "jetsam-api", - "version": "2.3.0", + "version": "2.5.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "jetsam-api", - "version": "2.3.0", + "version": "2.5.0", "license": "GPL-3.0+", "dependencies": { "@commander-lol/vault-client": "^0.1.1", @@ -28,7 +28,7 @@ "handlebars": "^4.7.6", "ioredis": "^4.17.3", "joi": "^17.3.0", - "jose": "^3.6.1", + "jose": "^4.6.1", "koa": "^2.13.0", "koa-bodyparser": "^4.3.0", "koa-compose": "^4.1.0", @@ -47,7 +47,7 @@ "node-fetch": "^2.6.1", "nodemailer": "^6.4.17", "oauth2-server": "^3.1.1", - "oidc-provider": "^7.10.1", + "oidc-provider": "git+ssh://git@github.com:Commander-lol/node-oidc-provider.git#de6429dd4aaab02c73a6d22faaee33efd78d4584", "pg": "^8.3.0", "pg-hstore": "^2.3.3", "pluralize": "^8.0.0", @@ -65,7 +65,8 @@ "jest": "^26.6.3", "nodemon": "^2.0.4", "prettier": "^2.2.1", - "supertest": "^6.1.3" + "supertest": "^6.1.3", + "umzug": "^3.1.1" } }, "node_modules/@babel/code-frame": { @@ -1356,6 +1357,18 @@ "resolved": "https://npm.lcr.gr/@root%2frequest/-/request-1.7.0.tgz", "integrity": "sha512-lre7XVeEwszgyrayWWb/kRn5fuJfa+n0Nh+rflM9E+EpC28yIYA+FPm/OL1uhzp3TxhQM0HFN4FE2RDIPGlnmg==" }, + "node_modules/@rushstack/ts-command-line": { + "version": "4.10.9", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.9.tgz", + "integrity": "sha512-TE3eZgHNVHOY3p8lp38FoNEJUr0+swPb24sCcYuwlC+MHgMGXyJNM+p7l3TKSBRiY01XShoL2k601oGwL00KlA==", + "dev": true, + "dependencies": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, "node_modules/@sendgrid/client": { "version": "7.4.2", "resolved": "https://npm.lcr.gr/@sendgrid%2fclient/-/client-7.4.2.tgz", @@ -1551,6 +1564,12 @@ "node": ">= 6" } }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true + }, "node_modules/@types/babel__core": { "version": "7.1.12", "resolved": "https://npm.lcr.gr/@types%2fbabel__core/-/babel__core-7.1.12.tgz", @@ -2986,6 +3005,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "node_modules/colors": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", + "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -7686,9 +7714,9 @@ } }, "node_modules/jose": { - "version": "3.6.1", - "resolved": "https://npm.lcr.gr/jose/-/jose-3.6.1.tgz", - "integrity": "sha512-AZ+dcXaYbX79uvqedXl7QMDkhpQBVXFezLRP734phyVw8EEcnwRIsOMLw4JAMJ+7Iyhv5Eb7isQUEZvqCCk6vA==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.6.1.tgz", + "integrity": "sha512-EFnufEivlIB6j7+JwaenYQzdUDs/McajDr9WnhT6EI0WxbexnfuZimpWX1GnobF6OnQsUFmWFXUXdWyZHWdQow==", "funding": { "url": "https://github.com/sponsors/panva" } @@ -8974,9 +9002,10 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, "node_modules/oidc-provider": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/oidc-provider/-/oidc-provider-7.10.1.tgz", - "integrity": "sha512-SRFVePq/ki76SbKB/vx7ach6mgc6iof2dtYOKMA88f3i1gZ6XKbqqxqyEVAj4n9L13nssUWJE9O4AyN8M0bNKA==", + "version": "7.10.6", + "resolved": "git+ssh://git@github.com/Commander-lol/node-oidc-provider.git#de6429dd4aaab02c73a6d22faaee33efd78d4584", + "integrity": "sha512-qXHx7oEjm0UgTHC+KLLCRzCyup5J/kNKGUxQOxmIG0xeA2IRSkYkBHZgElTulqrJNZfGiJYxMTO/Wk3KdgEUsA==", + "license": "MIT", "dependencies": { "@koa/cors": "^3.1.0", "cacheable-lookup": "^6.0.1", @@ -8990,7 +9019,7 @@ "nanoid": "^3.1.28", "object-hash": "^2.2.0", "oidc-token-hash": "^5.0.1", - "paseto2": "npm:paseto@^2.1.3", + "paseto": "^2.1.3", "quick-lru": "^5.1.1", "raw-body": "^2.4.1" }, @@ -9001,7 +9030,7 @@ "url": "https://github.com/sponsors/panva" }, "optionalDependencies": { - "paseto3": "npm:paseto@^3.0.0" + "paseto3": "npm:paseto@^3.1.0" } }, "node_modules/oidc-provider/node_modules/@sindresorhus/is": { @@ -9111,14 +9140,6 @@ "node": ">=10.6.0" } }, - "node_modules/oidc-provider/node_modules/jose": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.3.6.tgz", - "integrity": "sha512-A/JgZGUerqG2IMuxkUDBtZ4aTxg/l1Y+pt/QAAYiRAR3EFlxIE0Su0xdpB8tQcPZK5eudB7g1PHCZ5uHatbY+g==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/oidc-provider/node_modules/jsesc": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", @@ -9436,8 +9457,7 @@ "node": ">=0.10.0" } }, - "node_modules/paseto2": { - "name": "paseto", + "node_modules/paseto": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/paseto/-/paseto-2.1.3.tgz", "integrity": "sha512-BNkbvr0ZFDbh3oV13QzT5jXIu8xpFc9r0o5mvWBhDU1GBkVt1IzHK1N6dcYmN7XImrUmPQ0HCUXmoe2WPo8xsg==", @@ -9704,6 +9724,15 @@ "node": ">=4" } }, + "node_modules/pony-cause": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-1.1.1.tgz", + "integrity": "sha512-PxkIc/2ZpLiEzQXu5YRDOUgBlfGYBY8156HY5ZcRAwwonMk5W/MrJP2LLkG/hF7GEQzaHo2aS7ho6ZLCOvf+6g==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://npm.lcr.gr/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -10871,6 +10900,17 @@ "node": ">=10.0.0" } }, + "node_modules/sequelize-cli/node_modules/umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "dependencies": { + "bluebird": "^3.7.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/sequelize-pool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", @@ -11423,6 +11463,15 @@ } ] }, + "node_modules/string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-length": { "version": "4.0.1", "resolved": "https://npm.lcr.gr/string-length/-/string-length-4.0.1.tgz", @@ -12023,14 +12072,54 @@ } }, "node_modules/umzug": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", - "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-3.1.1.tgz", + "integrity": "sha512-sgMDzUK6ZKS3pjzRJpAHqSkvAQ+64Dourq6JfQv11i0nMu0/QqE3V3AUpj2pWYxFBaSvnUxKrzZQmPr6NZhvdQ==", + "dev": true, "dependencies": { - "bluebird": "^3.7.2" + "@rushstack/ts-command-line": "^4.7.7", + "emittery": "^0.10.2", + "fs-jetpack": "^4.1.0", + "glob": "^7.1.6", + "pony-cause": "^1.1.1", + "type-fest": "^2.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=12" + } + }, + "node_modules/umzug/node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/umzug/node_modules/fs-jetpack": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-4.3.1.tgz", + "integrity": "sha512-dbeOK84F6BiQzk2yqqCVwCPWTxAvVGJ3fMQc6E2wuEohS28mR6yHngbrKuVCK1KHRx/ccByDylqu4H5PCP2urQ==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.2", + "rimraf": "^2.6.3" + } + }, + "node_modules/umzug/node_modules/type-fest": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", + "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/undefsafe": { @@ -13723,6 +13812,18 @@ "resolved": "https://npm.lcr.gr/@root%2frequest/-/request-1.7.0.tgz", "integrity": "sha512-lre7XVeEwszgyrayWWb/kRn5fuJfa+n0Nh+rflM9E+EpC28yIYA+FPm/OL1uhzp3TxhQM0HFN4FE2RDIPGlnmg==" }, + "@rushstack/ts-command-line": { + "version": "4.10.9", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.9.tgz", + "integrity": "sha512-TE3eZgHNVHOY3p8lp38FoNEJUr0+swPb24sCcYuwlC+MHgMGXyJNM+p7l3TKSBRiY01XShoL2k601oGwL00KlA==", + "dev": true, + "requires": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, "@sendgrid/client": { "version": "7.4.2", "resolved": "https://npm.lcr.gr/@sendgrid%2fclient/-/client-7.4.2.tgz", @@ -13879,6 +13980,12 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" }, + "@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true + }, "@types/babel__core": { "version": "7.1.12", "resolved": "https://npm.lcr.gr/@types%2fbabel__core/-/babel__core-7.1.12.tgz", @@ -15071,6 +15178,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "colors": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", + "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -18734,9 +18847,9 @@ } }, "jose": { - "version": "3.6.1", - "resolved": "https://npm.lcr.gr/jose/-/jose-3.6.1.tgz", - "integrity": "sha512-AZ+dcXaYbX79uvqedXl7QMDkhpQBVXFezLRP734phyVw8EEcnwRIsOMLw4JAMJ+7Iyhv5Eb7isQUEZvqCCk6vA==" + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.6.1.tgz", + "integrity": "sha512-EFnufEivlIB6j7+JwaenYQzdUDs/McajDr9WnhT6EI0WxbexnfuZimpWX1GnobF6OnQsUFmWFXUXdWyZHWdQow==" }, "js-beautify": { "version": "1.11.0", @@ -19771,9 +19884,9 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, "oidc-provider": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/oidc-provider/-/oidc-provider-7.10.1.tgz", - "integrity": "sha512-SRFVePq/ki76SbKB/vx7ach6mgc6iof2dtYOKMA88f3i1gZ6XKbqqxqyEVAj4n9L13nssUWJE9O4AyN8M0bNKA==", + "version": "git+ssh://git@github.com/Commander-lol/node-oidc-provider.git#de6429dd4aaab02c73a6d22faaee33efd78d4584", + "integrity": "sha512-qXHx7oEjm0UgTHC+KLLCRzCyup5J/kNKGUxQOxmIG0xeA2IRSkYkBHZgElTulqrJNZfGiJYxMTO/Wk3KdgEUsA==", + "from": "oidc-provider@git+ssh://git@github.com:Commander-lol/node-oidc-provider.git#de6429dd4aaab02c73a6d22faaee33efd78d4584", "requires": { "@koa/cors": "^3.1.0", "cacheable-lookup": "^6.0.1", @@ -19787,8 +19900,8 @@ "nanoid": "^3.1.28", "object-hash": "^2.2.0", "oidc-token-hash": "^5.0.1", - "paseto2": "npm:paseto@^2.1.3", - "paseto3": "npm:paseto@^3.0.0", + "paseto": "^2.1.3", + "paseto3": "npm:paseto@^3.1.0", "quick-lru": "^5.1.1", "raw-body": "^2.4.1" }, @@ -19866,11 +19979,6 @@ } } }, - "jose": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.3.6.tgz", - "integrity": "sha512-A/JgZGUerqG2IMuxkUDBtZ4aTxg/l1Y+pt/QAAYiRAR3EFlxIE0Su0xdpB8tQcPZK5eudB7g1PHCZ5uHatbY+g==" - }, "jsesc": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", @@ -20102,8 +20210,8 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, - "paseto2": { - "version": "npm:paseto@2.1.3", + "paseto": { + "version": "2.1.3", "resolved": "https://registry.npmjs.org/paseto/-/paseto-2.1.3.tgz", "integrity": "sha512-BNkbvr0ZFDbh3oV13QzT5jXIu8xpFc9r0o5mvWBhDU1GBkVt1IzHK1N6dcYmN7XImrUmPQ0HCUXmoe2WPo8xsg==" }, @@ -20305,6 +20413,12 @@ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" }, + "pony-cause": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-1.1.1.tgz", + "integrity": "sha512-PxkIc/2ZpLiEzQXu5YRDOUgBlfGYBY8156HY5ZcRAwwonMk5W/MrJP2LLkG/hF7GEQzaHo2aS7ho6ZLCOvf+6g==", + "dev": true + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://npm.lcr.gr/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -21224,6 +21338,16 @@ "resolve": "^1.5.0", "umzug": "^2.3.0", "yargs": "^13.1.0" + }, + "dependencies": { + "umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "requires": { + "bluebird": "^3.7.2" + } + } } }, "sequelize-pool": { @@ -21675,6 +21799,12 @@ } } }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, "string-length": { "version": "4.0.1", "resolved": "https://npm.lcr.gr/string-length/-/string-length-4.0.1.tgz", @@ -22137,11 +22267,41 @@ } }, "umzug": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", - "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-3.1.1.tgz", + "integrity": "sha512-sgMDzUK6ZKS3pjzRJpAHqSkvAQ+64Dourq6JfQv11i0nMu0/QqE3V3AUpj2pWYxFBaSvnUxKrzZQmPr6NZhvdQ==", + "dev": true, "requires": { - "bluebird": "^3.7.2" + "@rushstack/ts-command-line": "^4.7.7", + "emittery": "^0.10.2", + "fs-jetpack": "^4.1.0", + "glob": "^7.1.6", + "pony-cause": "^1.1.1", + "type-fest": "^2.0.0" + }, + "dependencies": { + "emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true + }, + "fs-jetpack": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-4.3.1.tgz", + "integrity": "sha512-dbeOK84F6BiQzk2yqqCVwCPWTxAvVGJ3fMQc6E2wuEohS28mR6yHngbrKuVCK1KHRx/ccByDylqu4H5PCP2urQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.2", + "rimraf": "^2.6.3" + } + }, + "type-fest": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", + "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==", + "dev": true + } } }, "undefsafe": { diff --git a/package.json b/package.json index 5276081ffd28a3e7599b63629b955bf9d1512c90..ea10a5565ae2e730231a242aba6c0a9869429d8e 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "handlebars": "^4.7.6", "ioredis": "^4.17.3", "joi": "^17.3.0", - "jose": "^3.6.1", + "jose": "^4.6.1", "koa": "^2.13.0", "koa-bodyparser": "^4.3.0", "koa-compose": "^4.1.0", @@ -58,7 +58,7 @@ "node-fetch": "^2.6.1", "nodemailer": "^6.4.17", "oauth2-server": "^3.1.1", - "oidc-provider": "^7.10.1", + "oidc-provider": "git+ssh://git@github.com:Commander-lol/node-oidc-provider.git#de6429dd4aaab02c73a6d22faaee33efd78d4584", "pg": "^8.3.0", "pg-hstore": "^2.3.3", "pluralize": "^8.0.0", @@ -76,6 +76,7 @@ "jest": "^26.6.3", "nodemon": "^2.0.4", "prettier": "^2.2.1", - "supertest": "^6.1.3" + "supertest": "^6.1.3", + "umzug": "^3.1.1" } } diff --git a/scripts/jest.js b/scripts/jest.js index 36eb8faa049f070db0d53a7bb7c29338a76aafde..5bd90421f82df55f8268f4dc2f16973920fb07cc 100644 --- a/scripts/jest.js +++ b/scripts/jest.js @@ -2,6 +2,8 @@ const { execSync } = require('child_process') const bootstrap = require('../src/bootstrap') const { v4: uuid } = require('uuid') const { exec } = require('core/utils/process') +const Sequelize = require("sequelize"); +const {config} = require("bootstrap"); async function run() { process.env.NODE_ENV = 'testing' @@ -10,25 +12,77 @@ async function run() { const id = uuid().replace(/-/g, '') const dbname = `${ bootstrap.config('database.database') }_${ id }` - await bootstrap.invoke('db:fresh', [id, '--and-migrate'], false) + const pg = require('pg') + const conf = bootstrap.config('database') + const dbconf = { + user: conf.username, + password: conf.password, + host: conf.host, + database: conf.database, + port: conf.port, + application_name: `${ bootstrap.config('app.name') } Test Harness` + } + + console.log("[BOOT] Setting up database ", dbname) + let client = new pg.Client(dbconf) + await client.connect() + await client.query(`CREATE DATABASE ${ dbname }`) + + const { Sequelize } = require('sequelize') + const sqlconf = bootstrap.config('sequelize')['testing'] + const sql = new Sequelize( + dbname, + conf.username, + conf.password, + sqlconf, + ) + + const { Umzug, SequelizeStorage } = require('umzug') + const umzug = new Umzug({ + storage: new SequelizeStorage({ sequelize: sql }), + context: [sql.getQueryInterface(), Sequelize], + migrations: { + glob: 'database/migrations/*.js', + resolve: ({ name, path, context }) => { + // console.log(path, context, name) + return { + name, + up: () => require(path).up(...context), + down: () => require(path).down(...context), + } + } + } + }) + + console.log("[BOOT] Migrating database ", dbname) + await umzug.up() + await sql.close() try { - const runner = await exec('npx jest --forceExit --runInBand', { + console.log("[BOOT] Running tests ", dbname) + const runner = await exec('npx jest --env=node --forceExit --runInBand', { env: { ...process.env, DATABASE_NAME: dbname, + QUEUE_DRIVER: 'async', + CACHE_DRIVER: 'memory', SENTRY_ENABLED: false, }, stdio: 'inherit', }, true) + if (runner > 0) { + throw new Error(`Tests failed with code ${ runner }`) + } } finally { - await bootstrap.invoke('db:prune') - process.exit() + console.log("[BOOT] Dropping database ", dbname) + await client.query(`DROP DATABASE ${ dbname }`) + await client.end() } } run() + .then(() => process.exit()) .catch(e => { console.error(e) process.exit(1) diff --git a/src/app.js b/src/app.js index 91bf6668fdfa0f6813e5630c7a8a6dd29425374a..1fcec2c77849ef80ccb4f3bde943d69a023dd576 100644 --- a/src/app.js +++ b/src/app.js @@ -4,7 +4,7 @@ const logger = require('koa-logger') const bodyparser = require('koa-bodyparser') const etag = require('koa-etag') const session = require('koa-session') -const static = require('koa-static') +const files = require('koa-static') const mount = require('koa-mount') const createOIDCServer = require('domain/auth/oidc/OIDCServer') @@ -22,7 +22,12 @@ const serviceProvider = require('core/injection/ServiceProvider') const notFound = require("http/middleware/NotFoundHandler"); module.exports = async function createApp(app = new Koa()) { - const { fs } = require('bootstrap') + const { fs, boot } = require('bootstrap') + + if (process.env.NODE_ENV === 'testing') { + await boot() + } + const routers = require('http/routes') app.keys = [config('app.key')] @@ -35,7 +40,7 @@ module.exports = async function createApp(app = new Koa()) { app.use(etag({ weak: true })) app.use(bodyparser()) app.use(logger(s => requestLog(s))) - app.use(static(pathutil.resolve(__dirname + '/../public'))) + app.use(files(pathutil.resolve(__dirname + '/../public'))) app.use(notFound) app.use(async (ctx, next) => { diff --git a/src/core/utils/jwt.js b/src/core/utils/jwt.js index 53bc5074a203c5a86c0633a687ec0935a7f695d4..fe2208a7e332729ef11926762fe27de531d7c31e 100644 --- a/src/core/utils/jwt.js +++ b/src/core/utils/jwt.js @@ -39,10 +39,10 @@ exports.getKeys = () => { exports.getJWKS = async (type = 'pub') => { const { config } = require('bootstrap') const keys = exports.getKeys() - const { default: fromKeyLike } = require('jose/jwk/from_key_like') + const jose = require('jose') const key = keys[type] - const jwk = await fromKeyLike(key) + const jwk = await jose.exportJWK(key) const kid = config('app.security.key_id') return { @@ -97,11 +97,11 @@ exports.loadKeys = async () => { exports.sign = async payload => { const threadContext = require('core/injection/ThreadContext') const { config } = require('bootstrap') - const { default: SignJWT } = require('jose/jwt/sign') + const jose = require('jose') const { priv } = exports.getKeys() return await threadContext.profile('jwt.sign', JSON.stringify(payload), () => - new SignJWT(payload) + new jose.SignJWT(payload) .setIssuer(exports.jwtOptions.issuer) .setIssuedAt() .setProtectedHeader({ alg: 'RS256', kid: exports.jwtOptions.keyid_prefix + config('app.security.key_id') }) @@ -111,12 +111,12 @@ exports.sign = async payload => { exports.verify = async token => { const threadContext = require('core/injection/ThreadContext') - const { default: jwtVerify } = require('jose/jwt/verify') + const jose = require('jose') const { getKeys, jwtOptions } = exports const { pub } = getKeys() return await threadContext.profile('jwt.verify', undefined, async () => { - const { payload } = await jwtVerify(token, pub, jwtOptions) + const { payload } = await jose.jwtVerify(token, pub, jwtOptions) return payload }) } diff --git a/src/http/middleware/ErrorHandler.js b/src/http/middleware/ErrorHandler.js index 29985984bc80c85b4a333e9c38f1e3c69e8d3cea..5e6a0d55f8fb24429669fd51caced5b7cbf8ab29 100644 --- a/src/http/middleware/ErrorHandler.js +++ b/src/http/middleware/ErrorHandler.js @@ -8,9 +8,7 @@ module.exports = async (ctx, next) => { try { await next(ctx) } catch (e) { - if (e instanceof SafeModeError) { - console.error(e) - } else { + if (!(e instanceof SafeModeError)) { await SentryReporter.report(e, ctx) } hasHandledError = true diff --git a/src/http/middleware/NotFoundHandler.js b/src/http/middleware/NotFoundHandler.js index 4c2f0eff0841872856813bd2e7b7ded2699f2a66..573e9ef2d80a6dfee154dc73bf10e5ff866d9fab 100644 --- a/src/http/middleware/NotFoundHandler.js +++ b/src/http/middleware/NotFoundHandler.js @@ -5,6 +5,7 @@ module.exports = async (ctx, next) => { await next() await applyResponse(ctx) } catch(e) { + console.error(e) ctx.status = 500 await applyResponse(ctx, e) } diff --git a/tests/integration/authentication/Login.test.js b/tests/integration/authentication/Login.test.js index 16b61fcc556b323deb676243ff9b2844a6f4afcb..f989762bbe2655342fd40f68d28f798b4f903ecf 100644 --- a/tests/integration/authentication/Login.test.js +++ b/tests/integration/authentication/Login.test.js @@ -5,6 +5,7 @@ test('Logging in returns a token', async () => { const app = await createApp() const response = await request(app.callback()) .post('/api/register') + .set('Accept', 'application/json') .send({ email: 'login-returns-token@example.com', password: 'password', @@ -15,6 +16,7 @@ test('Logging in returns a token', async () => { const response2 = await request(app.callback()) .post('/api/login') + .set('Accept', 'application/json') .send({ email: 'login-returns-token@example.com', password: 'password', diff --git a/tests/integration/authentication/Registration.test.js b/tests/integration/authentication/Registration.test.js index 09bcf458fde13a95543b799b46567ee769bbeabc..9b4396194f05ebcb3f79e83f9ae8f8c5bc268749 100644 --- a/tests/integration/authentication/Registration.test.js +++ b/tests/integration/authentication/Registration.test.js @@ -13,6 +13,7 @@ test('Can register a new account', async () => { const app = await createApp() const response = await request(app.callback()) .post('/api/register') + .set('Accept', 'application/json') .send({ email: 'johnson@example.com', password: 'foo', @@ -30,6 +31,7 @@ test('Invalid registration request returns 400', async () => { const app = await createApp() const response = await request(app.callback()) .post('/api/register') + .set('Accept', 'application/json') .send({ incorrect: 'property' }) @@ -41,6 +43,7 @@ test('Two accounts cannot share an email address', async () => { const app = await createApp() const value1 = await request(app.callback()) .post('/api/register') + .set('Accept', 'application/json') .send({ email: 'example@example.com', password: 'foo', @@ -49,6 +52,7 @@ test('Two accounts cannot share an email address', async () => { const value2 = await request(app.callback()) .post('/api/register') + .set('Accept', 'application/json') .send({ email: 'example@example.com', password: 'foo', diff --git a/tests/integration/system/SafeMode.test.js b/tests/integration/system/SafeMode.test.js new file mode 100644 index 0000000000000000000000000000000000000000..9b5ddb210640159be5e1eb3f7cdef41f6b90b106 --- /dev/null +++ b/tests/integration/system/SafeMode.test.js @@ -0,0 +1,12 @@ +const request = require('supertest') +const createApp = require('app') + +test('Safe Mode Blocks Mutations', async () => { + process.env.DISABLE_MUTATION = 'true' + const app = await createApp() + const response = await request(app.callback()) + .post('/api/v2/metrics') + .set('Accept', 'application/json') + + expect(response.status).toBe(5400) +}) \ No newline at end of file