diff --git a/package-lock.json b/package-lock.json index bae46e0..da0d178 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,7 +70,7 @@ }, "@types/accepts": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", + "resolved": "http://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", "dev": true, "requires": { @@ -108,6 +108,12 @@ "@types/node": "*" } }, + "@types/cookiejar": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.0.tgz", + "integrity": "sha512-EIjmpvnHj+T4nMcKwHwxZKUfDmphIKJc2qnEMhSoOvr1lYEQpuRKRz8orWr//krYIIArS/KGGLfL2YGVUYXmIA==", + "dev": true + }, "@types/cookies": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.1.tgz", @@ -144,7 +150,7 @@ }, "@types/events": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", "dev": true }, @@ -217,6 +223,15 @@ "@types/node": "*" } }, + "@types/koa-bodyparser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@types/koa-bodyparser/-/koa-bodyparser-4.2.1.tgz", + "integrity": "sha512-dd6mVT30OmGYIOmNRF3269Bv+IJ68AVrvYcPViB7bYnzxk7nZyfeAsUx96lvXmaTpOGF4XZ7WDCuSOd7Npi6pw==", + "dev": true, + "requires": { + "@types/koa": "*" + } + }, "@types/koa-compose": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.2.tgz", @@ -307,6 +322,25 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, + "@types/superagent": { + "version": "3.8.5", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.5.tgz", + "integrity": "sha512-h7dQyzEGQFY3Ya8pIu0fxcWaMWC2DDSKR78gHrh6GVnXUqXo/+93wd4RObXA13rKp4ETyym3yq2A0AxROx9AxQ==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "@types/supertest": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.7.tgz", + "integrity": "sha512-GibTh4OTkal71btYe2fpZP/rVHIPnnUsYphEaoywVHo+mo2a/LhlOFkIm5wdN0H0DA0Hx8x+tKgCYMD9elHu5w==", + "dev": true, + "requires": { + "@types/superagent": "*" + } + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -328,6 +362,22 @@ "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", "dev": true }, + "aggregate-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", + "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=", + "requires": { + "clean-stack": "^1.0.0", + "indent-string": "^3.0.0" + }, + "dependencies": { + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" + } + } + }, "ajv": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", @@ -433,6 +483,12 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, "axobject-query": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", @@ -981,6 +1037,11 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, "cache-content-type": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", @@ -1073,6 +1134,11 @@ "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, + "clean-stack": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", + "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=" + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -1163,6 +1229,17 @@ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, + "co-body": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.0.0.tgz", + "integrity": "sha512-9ZIcixguuuKIptnY8yemEOuhb71L/lLf+Rl5JfJEUiDNJk0e02MBt7BPxR2GEh5mw8dPthQYR4jPI/BnS1MQgw==", + "requires": { + "inflation": "^2.0.0", + "qs": "^6.5.2", + "raw-body": "^2.3.3", + "type-is": "^1.6.16" + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -1187,12 +1264,27 @@ "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", "dev": true }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "dev": true }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1437,6 +1529,12 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, "cookies": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.3.tgz", @@ -1446,6 +1544,11 @@ "keygrip": "~1.0.3" } }, + "copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1571,6 +1674,12 @@ "object-keys": "^1.0.12" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -2083,6 +2192,12 @@ "strip-eof": "^1.0.0" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, "external-editor": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", @@ -2184,6 +2299,23 @@ "write": "^0.2.1" } }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", + "dev": true + }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -2343,6 +2475,14 @@ "resolved": "https://registry.npmjs.org/humanize-number/-/humanize-number-0.0.2.tgz", "integrity": "sha1-EcCvakcWQ2M1iFiASPF5lUFInBg=" }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "ieee754": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", @@ -2369,6 +2509,11 @@ "repeating": "^2.0.0" } }, + "inflation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", + "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2666,6 +2811,15 @@ } } }, + "koa-bodyparser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/koa-bodyparser/-/koa-bodyparser-4.2.1.tgz", + "integrity": "sha512-UIjPAlMZfNYDDe+4zBaOAUKYqkwAGcIU6r2ARf1UOXPAlfennQys5IiShaVeNf7KkVBlf88f2LeLvBFvKylttw==", + "requires": { + "co-body": "^6.0.0", + "copy-to": "^2.0.1" + } + }, "koa-compose": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", @@ -2695,6 +2849,34 @@ "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz", "integrity": "sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=" }, + "koa-jwt": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/koa-jwt/-/koa-jwt-3.5.1.tgz", + "integrity": "sha512-Wy1TZzyPdMw2X72HPhy9GPUy0BMxafS8Wq0JzvXCPi4pEBWQDtz1lzxYWpE2ghMuXWJ0vKKRrR5e+CyYGS8LBA==", + "requires": { + "jsonwebtoken": "8.3.0", + "koa-unless": "1.0.7", + "p-any": "1.1.0" + }, + "dependencies": { + "jsonwebtoken": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", + "integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==", + "requires": { + "jws": "^3.1.5", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1" + } + } + } + }, "koa-logger": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/koa-logger/-/koa-logger-3.2.0.tgz", @@ -2771,6 +2953,11 @@ } } }, + "koa-unless": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/koa-unless/-/koa-unless-1.0.7.tgz", + "integrity": "sha1-ud83XitNowQ5GNSGIlIMLAt58DI=" + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -3073,6 +3260,12 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, "mime-db": { "version": "1.37.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", @@ -3395,6 +3588,14 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-any": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-any/-/p-any-1.1.0.tgz", + "integrity": "sha512-Ef0tVa4CZ5pTAmKn+Cg3w8ABBXh+hHO1aV8281dKOoUHfX+3tjG2EaFcC+aZyagg9b4EYGsHEjz21DnEE8Og2g==", + "requires": { + "p-some": "^2.0.0" + } + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -3428,6 +3629,14 @@ "p-limit": "^1.1.0" } }, + "p-some": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-some/-/p-some-2.0.1.tgz", + "integrity": "sha1-Zdh8ixVO289SIdFnd4ttLhUPbwY=", + "requires": { + "aggregate-error": "^1.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -3627,6 +3836,35 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "qs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.6.0.tgz", + "integrity": "sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "dependencies": { + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + } + } + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -3781,8 +4019,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sax": { "version": "1.2.4", @@ -3963,6 +4200,34 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + } + }, + "supertest": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-3.3.0.tgz", + "integrity": "sha512-dMQSzYdaZRSANH5LL8kX3UpgK9G1LRh/jnggs/TI0W2Sz7rkMx9Y48uia3K9NgcaWEV28tYkBnXE4tiFC77ygQ==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^3.8.3" + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4273,6 +4538,11 @@ "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", "dev": true }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", diff --git a/package.json b/package.json index 3231692..2dce531 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@types/eslint-plugin-prettier": "^2.2.0", "@types/jsonwebtoken": "^8.3.0", "@types/koa": "^2.0.48", + "@types/koa-bodyparser": "^4.2.1", "@types/koa-logger": "^3.1.1", "@types/koa-router": "^7.0.35", "@types/lodash": "^4.14.119", @@ -15,6 +16,7 @@ "@types/mysql": "^2.15.5", "@types/node": "^10.12.18", "@types/prettier": "^1.15.2", + "@types/supertest": "^2.0.7", "chai": "^4.2.0", "concurrently": "^4.1.0", "cross-env": "^5.2.0", @@ -27,6 +29,7 @@ "eslint-plugin-react": "^7.12.0", "mocha": "^5.2.0", "prettier": "^1.15.3", + "supertest": "^3.3.0", "ts-node": "7.0.1", "ts-node-dev": "^1.0.0-pre.32", "tsconfig-paths": "^3.7.0", @@ -40,6 +43,8 @@ "bcrypt": "^3.0.3", "jsonwebtoken": "^8.4.0", "koa": "^2.6.2", + "koa-bodyparser": "^4.2.1", + "koa-jwt": "^3.5.1", "koa-logger": "^3.2.0", "koa-router": "^7.4.0", "lodash": "^4.17.11", diff --git a/src/app.ts b/src/app.ts index 23acbec..4a8aae0 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,8 +1,21 @@ import "reflect-metadata"; import * as Koa from "koa"; +import * as bodyParser from "koa-bodyparser"; +import * as jwt from "koa-jwt"; import * as logger from "koa-logger"; +import { config } from "~config"; +import { userRouter } from "~routes/users"; export const app = new Koa(); app.use(logger()); +app.use(bodyParser()); +app.use( + jwt({ + secret: config.jwtSecret, + passthrough: true, + }), +); + +app.use(userRouter.routes()).use(userRouter.allowedMethods()); diff --git a/src/routes/users.ts b/src/routes/users.ts new file mode 100644 index 0000000..657f255 --- /dev/null +++ b/src/routes/users.ts @@ -0,0 +1,62 @@ +import * as Router from "koa-router"; +import { IUserJWT, User } from "~entity/User"; + +export const userRouter = new Router(); + +userRouter.get("/users/user", async ctx => { + if (!ctx.state.user) { + ctx.throw(401); + } + + const jwt = ctx.state.user as IUserJWT; + + const user = await User.findOne(jwt.id); + + ctx.body = { errors: false, data: user.toAuthJSON() }; +}); + +userRouter.get("/users/login", async ctx => { + if (!ctx.request.body) { + ctx.throw(400); + } + const { username, password } = ctx.request.body as { + username: string | null; + password: string | null; + }; + if (!(username && password)) { + ctx.throw(400); + } + + const user = await User.findOne({ username }); + if (!user || !(await user.verifyPassword(password))) { + ctx.throw(404); + } + + ctx.body = { errors: false, data: user.toAuthJSON() }; +}); + +userRouter.get("/users/signup", async ctx => { + if (!ctx.request.body) { + ctx.throw(400); + } + + const { username, password } = ctx.request.body as { + username: string | null; + password: string | null; + }; + + if (!(username && password)) { + ctx.throw(400); + } + + const user = new User(username); + await user.setPassword(password); + + try { + await user.save(); + } catch (e) { + ctx.throw(400); + } + + ctx.body = { errors: false, data: user.toAuthJSON() }; +}); diff --git a/tests/integration/users.test.ts b/tests/integration/users.test.ts index ad11013..8b767f7 100644 --- a/tests/integration/users.test.ts +++ b/tests/integration/users.test.ts @@ -1,8 +1,14 @@ +import { expect } from "chai"; import { connect } from "config/database"; +import * as request from "supertest"; import { getConnection } from "typeorm"; +import { app } from "~app"; +import { IUserAuthJSON, User } from "~entity/User"; import { ISeed, seedDB } from "./util"; +const callback = app.callback(); + let seed: ISeed; describe("users", () => { @@ -18,13 +24,65 @@ describe("users", () => { seed = await seedDB(); }); - it("should get user", async () => {}); + it("should get user", async () => { + const response = await request(callback) + .get("/users/user") + .set({ Authorization: `Bearer ${seed.user1.toJWT()}` }) + .expect("Content-Type", /json/) + .expect(200); - it("should login user", async () => {}); + expect(response.body.errors).to.be.false; - it("should not login user with wrong password", async () => {}); + const { jwt: _, ...user } = response.body.data as IUserAuthJSON; - it("should signup user", async () => {}); + expect(user).to.deep.equal(seed.user1.toJSON()); + }); - it("should not signup user with duplicate username", async () => {}); + it("should login user", async () => { + const response = await request(callback) + .get("/users/login") + .send({ username: "User1", password: "User1" }) + .expect("Content-Type", /json/) + .expect(200); + + expect(response.body.errors).to.be.false; + + const { jwt: _, ...user } = response.body.data as IUserAuthJSON; + + expect(user).to.deep.equal(seed.user1.toJSON()); + }); + + it("should not login user with wrong password", async () => { + const response = await request(callback) + .get("/users/login") + .send({ username: "User1", password: "asdf" }) + .expect(404); + + expect(response.body).to.deep.equal({}); + }); + + it("should signup user", async () => { + const response = await request(callback) + .get("/users/signup") + .send({ username: "NUser1", password: "NUser1" }) + .expect("Content-Type", /json/) + .expect(200); + + expect(response.body.errors).to.be.false; + + const { jwt: _, ...user } = response.body.data as IUserAuthJSON; + + const newUser = await User.findOneOrFail({ username: "NUser1" }); + + expect(user).to.deep.equal(newUser.toJSON()); + }); + + it("should not signup user with duplicate username", async () => { + const response = await request(callback) + .get("/users/signup") + .send({ username: "User1", password: "NUser1" }) + .expect(400); + + expect(response.body).to.deep.equal({}); + }); }); diff --git a/tsconfig.json b/tsconfig.json index 9ccf7df..337296d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "lib": [ "es2017" ], - "target": "es6", + "target": "es2017", "module": "commonjs", "moduleResolution": "node", "outDir": "./dist",