269 Commits

Author SHA1 Message Date
967ef4e440 Updates
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-13 10:44:21 -04:00
d9285e4bec Working setups for dev and staging! (mostly)
All checks were successful
continuous-integration/drone/push Build is passing
TODO: Still no access to routes on staging... hmmm...
2023-05-12 15:37:32 -04:00
17949255d3 Maybe with a shell script...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-12 15:30:38 -04:00
c6e5eaf3a1 Def not
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-12 12:51:22 -04:00
0e220c0cf0 Remove console logging...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-12 08:37:52 -04:00
ebfe4339dc a lil logging
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-12 08:23:17 -04:00
0d3ca5382b db init script running, but no user... hmmmm 2023-05-12 08:20:41 -04:00
4477af601a Remove git attempts
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-12 08:13:05 -04:00
3b27300249 force yes
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-12 07:58:23 -04:00
47c4f4816c apt?
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-12 07:53:35 -04:00
95fdd8cf45 nope
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 22:57:06 -04:00
f7f6dcae12 Goodbye warnings?
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-11 22:50:41 -04:00
62a917677d Perhaps, more correct...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 22:17:17 -04:00
717e651cf9 Let's try this...
Some checks failed
continuous-integration/drone/push Build was killed
2023-05-11 22:08:27 -04:00
25688e1f03 Nope
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 22:00:49 -04:00
050a4f2b39 Or this?
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 21:27:56 -04:00
36093f0fb5 Or this?
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 21:25:20 -04:00
b9d5683d22 Arg...s.
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 21:20:24 -04:00
0b95587f53 Again...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 20:20:06 -04:00
486ef52745 wrong version
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 20:13:30 -04:00
ca6a6a9ab3 Bringing back the mongo build stage...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 20:02:53 -04:00
676124f23e Tried this before..
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-11 19:35:32 -04:00
d25755775e Likely not
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-11 19:02:27 -04:00
71904a53d9 Undo
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 18:36:22 -04:00
3dd7ccdcdc Giving up on a non-root user for now...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 13:00:34 -04:00
c8e08ef567 Add db and user...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-11 12:42:03 -04:00
cfad224c8d Revert "More paths"
All checks were successful
continuous-integration/drone/push Build is passing
This reverts commit 43dcdf4e6a.
2023-05-11 07:56:32 -04:00
43dcdf4e6a More paths
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 21:46:12 -04:00
9e3f7e2714 More path fixes
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 20:07:25 -04:00
4982175342 Fix paths
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 20:06:26 -04:00
65ff23e406 Shouldn't matter... directory structure
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 20:04:27 -04:00
a07e4ad9cc Muahahahaha
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 19:38:21 -04:00
4d813c6c2c And this
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 19:29:34 -04:00
9b0b9baf16 Give this a try (but it likely will have no effect) 2023-05-10 19:27:38 -04:00
9edbcc0bc2 Use the suboptimal...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 14:32:31 -04:00
12bff5848a Bring back the separate build step
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 14:21:52 -04:00
1bb5151fce Was the mongo version really the problem all along?
Some checks failed
continuous-integration/drone/push Build was killed
2023-05-10 14:20:55 -04:00
75c6af122f Reollback
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 14:01:38 -04:00
da36606af3 Again...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 13:50:13 -04:00
c3a689a007 DUH.
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 13:29:38 -04:00
b0ed748712 ??
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 13:28:04 -04:00
08a5b44660 hmmm 2023-05-10 13:19:49 -04:00
c80856f3c5 Adding the build back...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 13:16:03 -04:00
70737658c7 Hmmm..,.
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 13:14:09 -04:00
ebf0c6d970 Some crazy shit right here... mongo in the Dockerfile
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 13:09:30 -04:00
c92cefa903 This should work, but is suboptimal
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 12:40:16 -04:00
63e4270c89 La la la
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 12:33:16 -04:00
721edb71a1 - Build the db?
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 12:18:48 -04:00
8f20452e1a Sigh...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 11:47:08 -04:00
de58630958 Ha.
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-10 11:42:39 -04:00
f61b2b4535 Temp folder?
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-10 11:41:13 -04:00
6863d64112 Changes..
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 11:30:15 -04:00
aa52473f90 Ugh
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 11:15:43 -04:00
465e47fc10 Symlinks?
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 11:03:57 -04:00
3a721987dd This absolutely won't work...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 10:47:29 -04:00
2792753d3d Change volume inclusion back
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 10:34:47 -04:00
af6184d581 More tweaks
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 10:13:23 -04:00
40a3cdabc9 trying again... same ol mongo-init
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 10:04:09 -04:00
08e6af2eae - Trying to fix the mongo init
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-10 10:01:17 -04:00
09332aca24 fixed clone issue
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-10 09:54:33 -04:00
b161f926a9 Merge pull request 'Resolve branch name issue in pipeline trigger' (#8) from bugfix/pipeline-boken into develop
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #8
2023-05-10 13:50:40 +00:00
c406d6226c Resolve branch name issue in pipeline trigger
All checks were successful
continuous-integration/drone/pr Build is passing
2023-05-10 09:45:01 -04:00
74fd2bf32c Merge pull request 'Working Local Dev' (#7) from feature/working-local-dev into develop
Reviewed-on: #7
2023-05-10 13:40:42 +00:00
377300d288 Merge branch 'feature/working-local-dev' of ssh://git.mifi.dev:12022/mifi/auth into feature/working-local-dev
All checks were successful
continuous-integration/drone/pr Build is passing
2023-05-10 09:36:56 -04:00
83cc9be24c Drone pipeline fixes 2023-05-10 09:36:33 -04:00
4eaf354912 Merge branch 'develop' into feature/working-local-dev 2023-05-10 13:35:17 +00:00
c9a8e0746a Last second changes 2023-05-10 09:33:45 -04:00
07cca921bf Lots of updates! Working in local dev... not sure about staging yet... 2023-05-10 09:15:49 -04:00
cd980f2af9 Merge pull request 'feature/deploy-from-image-2' (#4) from feature/deploy-from-image-2 into main
Reviewed-on: #4
2023-05-10 00:48:40 +00:00
0e02c8ab15 add develop branch pr's to test checks
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone Build is failing
2023-05-09 20:39:35 -04:00
01cb2818ff Perhaps this will work! 2023-05-09 20:38:01 -04:00
67c84a7254 Merge pull request 'Switch to docker image for deploy' (#3) from feature/deploy-from-image into main
Reviewed-on: #3
2023-05-10 00:32:10 +00:00
5b15fcd60f Merge branch 'main' into feature/deploy-from-image
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone Build was killed
2023-05-10 00:27:59 +00:00
1e1eac9dd6 Switch to docker image for deploy
All checks were successful
continuous-integration/drone/pr Build is passing
2023-05-09 20:27:28 -04:00
0d2ffe0f54 Merge pull request 'Probably not...' (#2) from feature/updated_compose into main
Reviewed-on: #2
2023-05-10 00:07:49 +00:00
991dc32ce4 Some extra changes
All checks were successful
continuous-integration/drone/pr Build is passing
2023-05-09 20:04:11 -04:00
d6a72ace83 Probably not...
All checks were successful
continuous-integration/drone/pr Build is passing
2023-05-09 19:43:58 -04:00
7a0d5dc48c Merge branch 'release/0.0.37'
# Conflicts:
#	package.json
2023-05-09 19:36:14 -04:00
4ed4b6e5f4 update version
Some checks failed
continuous-integration/drone/pr Build is failing
2023-05-09 19:33:02 -04:00
4499e20e77 - Check that update route is authenticated 2023-05-09 19:28:27 -04:00
fbc1e55e5c Merge branch 'main' of ssh://git.mifi.dev:12022/mifi/auth 2023-05-09 19:15:25 -04:00
653fc7d52f promnotions 2023-05-09 19:15:01 -04:00
84881edb61 promnotions 2023-05-09 19:14:04 -04:00
c8b1b72694 New pipeline eventing 2023-05-09 19:08:17 -04:00
73cd1d794a Finalized drone pipeline (mostly)
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-09 18:52:31 -04:00
28ac23d8f2 Or one more...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-09 18:30:26 -04:00
71b7519a53 Last try then go with what works
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-09 18:28:53 -04:00
28ee1a9d1e One works... but the other...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-09 18:27:49 -04:00
f327c6e06e revert
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-09 18:18:14 -04:00
799ff00f9c Update pipeline. Again. Day 900 and something.
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-09 09:17:36 -04:00
369e3f4b5c !! 2023-05-08 19:26:53 -04:00
3788de2609 ??
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-08 19:24:42 -04:00
0f9aafe418 ........
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-08 19:15:07 -04:00
13b90e9ee6 .....
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 19:13:44 -04:00
6e19a6217d Go!
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-08 19:08:55 -04:00
34fd4e7304 ...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 19:05:41 -04:00
5e04012aa4 Zoom!
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 18:59:13 -04:00
e8f2928543 Go!
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 18:53:26 -04:00
91a3b2fabf Do just one thing...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 18:40:38 -04:00
964b9a03ef New pipeline...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 18:31:24 -04:00
bf693645d4 Lordy...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 18:22:37 -04:00
082b4826c2 image_pull_secrets
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 16:59:12 -04:00
e68c3002d8 And again...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 16:37:43 -04:00
30d2f4a644 Go!
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 16:32:52 -04:00
875a45f2b8 Perchance to dream...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 16:18:00 -04:00
6bf7afbe09 Fix for deploy...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 16:01:07 -04:00
5c94dbbff5 Maybe? Maybe not... 2023-05-08 15:59:56 -04:00
cb44eb1fab Hmmm. More trouble with secrets
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 15:53:27 -04:00
df63d7947f better secret file
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 15:47:20 -04:00
01a5ff907c Perhaps a big duh.
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 15:37:18 -04:00
e22e3d8bc3 Muahahahaha 2023-05-08 15:33:48 -04:00
efecd78355 Publishing FTW
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 15:15:50 -04:00
ed4246ba0e testing secrets...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 15:08:49 -04:00
4acc228fe3 This one seems to be valid
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 14:57:15 -04:00
42279b0592 This. 2023-05-08 14:52:26 -04:00
e417ab64d8 Ah ha! Finally.
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-08 14:22:19 -04:00
93b11c3a35 Fallback to old working
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-08 14:07:40 -04:00
1ef2c4919e Maybe these odd changes?
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-07 00:57:46 -04:00
6ff8f74317 Or this?
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-07 00:55:59 -04:00
bf70ca98f3 Or this...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-07 00:54:41 -04:00
52e5befd93 Doubtful...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-07 00:53:29 -04:00
a047b49073 Last try, then pack 2023-05-06 10:18:39 -04:00
59b20578bb Maybe
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 10:15:03 -04:00
cdd6c6a72a Dammit
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 10:12:30 -04:00
1d16473d2d Ah ha!
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 10:10:02 -04:00
cd2bef9811 So broken...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 10:00:17 -04:00
62118b6d64 ERGGGGG
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 09:57:46 -04:00
8290b332fb Ugh
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 09:56:00 -04:00
61236719f4 Or this...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 09:55:09 -04:00
aa699d5009 Testing this... 2023-05-06 09:48:31 -04:00
9a4f9cdf4c Hmmm 2023-05-06 09:48:00 -04:00
5532fc51a9 Unbroken? 2023-05-06 09:45:05 -04:00
99db648a36 - Endlessly fighting the ENV - I should be loading from the package... 2023-05-06 09:40:25 -04:00
adcab6afcb Double dollar
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 09:28:24 -04:00
8e40c0a06c Tweaking the ENV
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 09:19:31 -04:00
db5e4858b8 More ENV updates
Some checks failed
continuous-integration/drone/push Build was killed
2023-05-06 09:10:45 -04:00
d800311ae7 - ENV updates
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 09:08:15 -04:00
32fdde5d90 - The missing env variables...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 08:43:26 -04:00
2eacdaeece Tweaks
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-06 01:38:00 -04:00
827bce6e1b Updates for staging
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-06 01:15:11 -04:00
50c74fdb71 I think it is working now...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-06 00:48:27 -04:00
42f091489e Who knows what happens next...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-05 18:14:20 -04:00
995dd9a015 A whole new world...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-05 11:22:26 -04:00
5b0c9ba72d Escape the interpolation
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-05 11:14:31 -04:00
d745869cc0 Last bits to make it whole again...
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-05 11:10:13 -04:00
e6389d8b9b More tweaks... 2023-05-05 11:05:18 -04:00
47f1bdf485 More path fixes...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-05 10:56:33 -04:00
bc96664b7c Path fixes ... and the dumbest environment error yet...
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-05 10:53:42 -04:00
04ec6e2de3 Hmmmm
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-05 10:42:22 -04:00
ba31f4b8be More changes
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-05 10:01:42 -04:00
d5f9bc4d05 fix bad commands
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-05 09:20:14 -04:00
ad9ffc89b5 With links and fixed names...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-05 09:09:06 -04:00
f482750d08 this may break everything...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-05 08:47:54 -04:00
7b77df0c4c v0.0.13 - fixed triggers perhaps...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-05 08:32:17 -04:00
8ee5d627aa Resolving stupid errors
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-05 08:21:02 -04:00
775dd60b56 Mostly passing pipelines, still a broken deploy... 2023-05-05 08:19:29 -04:00
b3365607c5 Muahahahha 2023-05-04 23:28:40 -04:00
96058995be New approach...
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-04 23:19:45 -04:00
1d43b78590 More...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 23:12:09 -04:00
243682758a clean-up
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 23:07:48 -04:00
695c4d84e8 Add npmrc, update version, pipeline tweaks - re-enable pipeline in full
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-04 23:05:49 -04:00
25908dd9d7 Failing on the same old errors...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 22:18:19 -04:00
34a28b8134 No cache
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-04 22:08:27 -04:00
7e1f9a1f33 So close I can taste it...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-04 22:00:41 -04:00
f0ba205a58 Closer? that was a new error...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-04 21:51:54 -04:00
1a717cd83e Not likely....
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-04 21:49:37 -04:00
1e932d97c8 Probably not 2023-05-04 21:43:58 -04:00
d879de2a6b Maybe a fix for the volume syntax?
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 21:41:00 -04:00
34e3eb04af Ooops
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is failing
2023-05-04 21:31:16 -04:00
ff5f88588e Auth? 2023-05-04 21:30:25 -04:00
ac5c09b7da Or maybe add the registry to the package.json...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 21:17:59 -04:00
d1b42fe79f Remove registry from package.json
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 21:13:01 -04:00
3d32c77bd1 That command never played nice...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 21:05:57 -04:00
8e077810f5 Maybe these path changes will do the trick fixing the volume issues
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-04 21:04:29 -04:00
5e0621e37d Copy env into workspace?
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 20:59:54 -04:00
e6f9f9b523 Fix naming collision
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 20:53:13 -04:00
1c5fdabca6 Recombine Steps
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-04 20:48:13 -04:00
7bbb4bb036 A bit more...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 20:39:38 -04:00
159f87d07e HOST!
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 20:36:07 -04:00
244db86113 Trying with the .env file copied in
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 20:27:29 -04:00
00d9a4f734 Rollback!
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 20:21:15 -04:00
b7a3c12eff again
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-04 19:57:25 -04:00
8e263d7ace Rollback 2023-05-04 19:54:36 -04:00
641cbcfd47 but why?
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-04 19:51:44 -04:00
8af84d42e5 Broken?
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-04 19:44:57 -04:00
d31a47f46c This!
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-04 19:42:30 -04:00
ddb8ad0948 Or...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 19:40:33 -04:00
73cb0c23f5 Or this?
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 19:37:08 -04:00
59738f5711 Hmmm...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 19:33:52 -04:00
f3ff19098b privileged
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 12:28:32 -04:00
8bc852fa7d Secrets! 2023-05-04 12:26:23 -04:00
8e06b98695 Parallel publishing
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 12:15:59 -04:00
809255baa6 Last try before lunch
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 12:12:44 -04:00
21e80ca883 try dind
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 12:09:53 -04:00
cfb7c7e453 Do the things. Again.
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 12:04:53 -04:00
82498e7714 not frozen
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 11:44:52 -04:00
87a611459a ...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 11:43:02 -04:00
0a09208766 ... 2023-05-04 11:42:32 -04:00
99ce364dc4 Ugh 2023-05-04 11:41:54 -04:00
2daa33f3ac Still can't publish or deploy... 2023-05-04 11:41:16 -04:00
2814c6820b Perhaps...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 11:32:09 -04:00
d9cafe009d Pipeline triggers 2023-05-04 11:28:12 -04:00
d011f15136 - Resolve version number issue
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-04 11:25:58 -04:00
ee398feeb9 Update pipelines
Some checks are pending
continuous-integration/drone/push Build is running
2023-05-04 11:23:28 -04:00
c2d9f8be5a Update to v 0.0.4 2023-05-04 11:17:52 -04:00
5f69193b81 Annoying ass shit 2023-05-03 23:07:44 -04:00
2a13a433e1 this 2023-05-03 23:06:37 -04:00
b094ae2c9a Deploy 2023-05-03 23:00:55 -04:00
e48037a7d4 Tweaks 2023-05-03 22:57:22 -04:00
ecfa12154d Up version / publish 2023-05-03 22:37:21 -04:00
aa2611b68d Updates
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-03 19:46:24 -04:00
0a7bbb96c0 Why not?
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-03 17:05:53 -04:00
96c7061ace try this 2023-05-03 16:52:19 -04:00
6b39d138de Deploy reporting
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-03 16:40:30 -04:00
0d3571e859 last try then pause
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-03 16:36:07 -04:00
2a7172ddfe ?? 2023-05-03 16:33:00 -04:00
97ed5f1f43 ? 2023-05-03 16:31:42 -04:00
0e53dd8132 brokeb? 2023-05-03 16:29:03 -04:00
06c9c1d896 test 2023-05-03 16:26:26 -04:00
f29b50120f typo 2023-05-03 15:34:07 -04:00
cb75c651b9 Done 2023-05-03 15:33:24 -04:00
c83db307ad Dammit 2023-05-03 15:29:42 -04:00
45964e4f13 Ugh 2023-05-03 15:23:13 -04:00
0e3ff90e09 Done 2023-05-03 15:17:31 -04:00
8031b12940 Hmmm. 2023-05-03 15:13:56 -04:00
9073408f6d What about... 2023-05-03 15:11:41 -04:00
943ffe96d1 Erm..
Some checks failed
continuous-integration/drone/push Build was killed
2023-05-03 15:05:46 -04:00
6d07bbd9ad - Changes 2023-05-03 15:03:13 -04:00
51b3d2c7c6 A stab at deploying
Some checks failed
continuous-integration/drone/push Build was killed
2023-05-03 15:00:10 -04:00
32bfbd7adc Finishing touches to publish
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-03 11:38:41 -04:00
dc72cefece Reorganizing
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-03 11:12:59 -04:00
27a78dd471 Better build pipeline?
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-02 22:55:02 -04:00
8ca639058b - stuff and things
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 22:50:23 -04:00
39ba4965e0 Tweaks
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 22:10:47 -04:00
e3a0e36560 Adding jest
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 21:58:29 -04:00
68f58329e8 - Connecting the dots?
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 21:47:45 -04:00
5fba4c6643 Linty fresh and pretty
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 20:54:14 -04:00
f105ce537f Prettier! 2023-05-02 20:36:40 -04:00
adb3866700 linty fresh(er)
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 20:23:19 -04:00
d47c229178 - Poop.
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 20:06:01 -04:00
a6634bc939 Always the typos...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 19:39:26 -04:00
52870d9bf8 Maybe some conditional icons...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 19:34:06 -04:00
5a35f3fef5 Red stupid...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 19:29:48 -04:00
3f0d476885 Oh yeah...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 19:22:01 -04:00
9c06dbed5b I think I now get the pipeline concept
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 19:16:42 -04:00
add0b91fdd typo
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 19:08:44 -04:00
ef860f3bbe Back in time... 2023-05-02 19:04:56 -04:00
85e7839f21 update order? 2023-05-02 18:47:06 -04:00
c76251bbe3 .. 2023-05-02 18:45:53 -04:00
5a53f486f6 This 2023-05-02 18:43:12 -04:00
136c7acb47 This pipeline, maybe...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 18:39:20 -04:00
ae015ccd56 Hmmm
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 18:12:47 -04:00
b95dfb8cf3 More drone reporting updates
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-02 18:02:57 -04:00
52454649f5 Drone reporting
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-02 18:01:16 -04:00
31aa388c69 Stage it all
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 11:59:45 -04:00
0a9d37c9e8 Adding build to the pipeline
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 11:51:00 -04:00
92d43edd7a Only warning now... Green pipeline?
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-02 11:45:41 -04:00
4176b0be51 New drone bits
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 11:16:46 -04:00
63dd15ea83 Add Prettier to the mix
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 11:07:01 -04:00
43e5920658 Remove unneeded packages
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-02 10:57:27 -04:00
7f5765aaaa Finally have prettier and linting maybe working
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-02 10:54:45 -04:00
34acea15a2 - Linty fresh...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 02:04:09 -04:00
14fe45fc9c Updates 2023-05-02 01:51:09 -04:00
fda0e160d4 Yarn already be there...
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 01:45:47 -04:00
6d35d7d3ab - Litle change
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 01:44:00 -04:00
9a15e5230d Update pipeline
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-02 01:32:18 -04:00
e1f59a7ace Lint, not test
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-02 01:27:41 -04:00
2eadb66246 Big commit again...
Some checks failed
continuous-integration/drone/push Build encountered an error
2023-05-02 01:26:01 -04:00
52782efc2e Tweaks 2023-05-02 01:18:43 -04:00
61 changed files with 5029 additions and 2558 deletions

282
.drone.yml Normal file
View File

@@ -0,0 +1,282 @@
kind: pipeline
type: docker
name: Test Pipeline
workspace:
path: /drone/auth
steps:
- name: yarn install
image: node:latest
commands:
- yarn install
- name: Code Style Checks
image: node:latest
commands:
- yarn prettier
- name: Lint
image: node:latest
commands:
- yarn lint
- name: Unit Tests
image: node:latest
commands:
- yarn test
- name: Send Test Status Notification
image: plugins/webhook
settings:
urls: https://lab.mifi.dev/hooks/9p65zpagctgkmndo8nwwm4199r
content_type: application/json
template: |
{
"icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
"text": "[{{ repo.name }} - Build # {{ build.number }}] Code Quality Checks {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
"username":"DroneBot"
}
when:
status:
- success
- failure
- name: Build
image: node:latest
commands:
- yarn build
- name: Send Build Status Notifications
image: plugins/webhook
settings:
urls: https://lab.mifi.dev/hooks/9p65zpagctgkmndo8nwwm4199r
content_type: application/json
template: |
{
"icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
"text": "[{{ repo.name }} - Build # {{ build.number }}] Build package {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
"username":"DroneBot"
}
when:
status:
- success
- failure
trigger:
branch:
- main
- develop
event:
- pull_request
---
kind: pipeline
type: docker
name: Publish Pipeline
workspace:
path: /drone/auth
steps:
- name: Build Package
image: node:latest
commands:
- yarn install
- yarn build
- name: Publish NPM
image: node:20-alpine
failure: ignore
commands:
- yarn publish -t ${DRONE_TAG}
volumes:
- name: npmrc
path: /drone/auth/.npmrc
- name: Report NPM Publish Status
image: plugins/webhook
settings:
urls: https://lab.mifi.dev/hooks/ccw34hdf7tgbjmzp96nptn938r
content_type: application/json
template: |
{
"icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
"text": "[{{ repo.name }} - New npm package release {{tag}} from # {{ build.number }}] Deploy {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
"username":"DroneBot"
}
when:
status:
- success
- failure
- name: Publish Image
image: plugins/docker
settings:
auto_tag: true
repo: git.mifi.dev/mifi/mifi/auth
registry: git.mifi.dev
debug: true
ssh-agent-key:
from_secret: reg_token
username: <token>
password:
from_secret: reg_token
secrets: [reg_token]
- name: Report Image Publish Status
image: plugins/webhook
settings:
urls: https://lab.mifi.dev/hooks/ccw34hdf7tgbjmzp96nptn938r
content_type: application/json
template: |
{
"icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
"text": "[{{ repo.name }} - New docker image release {{tag}} from # {{ build.number }}] Deploy {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
"username":"DroneBot"
}
when:
status:
- success
- failure
volumes:
- name: dockerconfig
host:
path: /volume1/docker/dockerconfig.json
- name: dockersock
host:
path: /var/run/docker.sock
- name: npmrc
host:
path: /volume1/docker/beethoven/labs-auth/.npmrc
depends_on:
- Test Pipeline
trigger:
event:
- tag
---
kind: pipeline
type: docker
name: Staging Deploy Pipeline
workspace:
path: /drone/auth
steps:
- name: Deploy Container
image: docker
privileged: true
environment:
CONTAINER_PREFIX: staging
HOST: area51.mifi.dev
ROUTE_PREFIX: /auth
PORT: 9001
commands:
- docker compose -f docker-compose.staging-build.yml build --pull --no-cache
- docker compose -f docker-compose.staging-build.yml up --remove-orphans --force-recreate --wait
volumes:
- name: env-secrets
path: /drone/auth/staging.env
- name: dockersock
path: /var/run/docker.sock
- name: dockerconfig
path: /drone/auth/.docker/config.json
- name: Send Status Notifications
image: plugins/webhook
privileged: true
settings:
urls: https://lab.mifi.dev/hooks/ccw34hdf7tgbjmzp96nptn938r
content_type: application/json
template: |
{
"icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
"text": "[{{ repo.name }} - Build # {{ build.number }}] Deploy {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
"username":"DroneBot"
}
when:
status:
- success
- failure
volumes:
- name: dockerconfig
host:
path: /volume1/docker/dockerconfig.json
- name: dockersock
host:
path: /var/run/docker.sock
- name: env-secrets
host:
path: /volume1/docker/beethoven/labs-auth/staging.env
depends_on:
- Test Pipeline
trigger:
branch:
- develop
event:
- push
---
kind: pipeline
type: docker
name: Production Deploy Pipeline
workspace:
path: /drone/auth
clone:
disable: true
steps:
- name: Deploy Container
image: docker
privileged: true
environment:
CONTAINER_PREFIX: staging
HOST: area51.mifi.dev
ROUTE_PREFIX: /auth
PORT: 9001
commands:
- docker compose -f docker-compose.production-build.yml pull
- docker compose -f docker-compose.production-build.yml build --no-cache
- docker compose -f docker-compose.production-build.yml rm --stop
- docker compose -f docker-compose.production-build.yml up --wait
volumes:
- name: env-secrets
path: /drone/auth/production.env
- name: dockersock
path: /var/run/docker.sock
- name: dockerconfig
path: /drone/auth/.docker/config.json
- name: Send Status Notifications
image: plugins/webhook
privileged: true
settings:
urls: https://lab.mifi.dev/hooks/ccw34hdf7tgbjmzp96nptn938r
content_type: application/json
template: |
{
"icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
"text": "[{{ repo.name }} - Build # {{ build.number }}] Deploy {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
"username":"DroneBot"
}
when:
status:
- success
- failure
volumes:
- name: dockerconfig
host:
path: /volume1/docker/dockerconfig.json
- name: dockersock
host:
path: /var/run/docker.sock
- name: env-secrets
host:
path: /volume1/docker/beethoven/labs-auth/staging.env
depends_on:
- Test Pipeline
trigger:
event:
- promote
target:
- production

31
.env.dev Normal file
View File

@@ -0,0 +1,31 @@
HOST=localhost
PORT=9001
ROUTE_PREFIX=/auth
LOGIN_ROUTE=/login
RESET_ROUTE=/reset
# DB_ADMIN_USERNAME=root
# DB_ADMIN_PASSWORD=password
DB_USERNAME=user
DB_PASSWORD=password
DB_NAME=auth
MONGO_INITDB_ROOT_USERNAME=$DB_USERNAME
MONGO_INITDB_ROOT_PASSWORD=$DB_PASSWORD
MONGO_INITDB_DATABASE=$DB_NAME
SESSION_KEY=shjhakjfhfjdshjksdhfdshfhfduyeyb73te4
JWT_AUDIENCE=Grow.io
JWT_ISSUER=Grow Latch
JWT_SECRET=Th!sIs a d3v3lopm3nt server SEcr¢T.
LOGIN_VALID_TIME=12H
RESET_VALID_MINUTES=15
DEFAULT_TOKEN_DAYS=1
CONTAINER_PREFIX=dev
SERVICE_NAME=auth-service
ENV=development

19
.eslintrc.js Normal file
View File

@@ -0,0 +1,19 @@
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/errors',
'plugin:prettier/recommended',
'prettier',
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
settings: {
'import/parsers': {
'@typescript-eslint/parser': [".ts", ".tsx"],
},
'import/resolver': 'typescript',
},
root: true,
};

7
.prettierrc.js Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
parser: 'typescript',
printWidth: 120,
trailingComma: 'all',
tabWidth: 4,
singleQuote: true,
};

28
Dockerfile Normal file
View File

@@ -0,0 +1,28 @@
ARG ENV=production
ARG MONGO_VERSION=latest
ARG PORT=9001
## mongo build stage
FROM mongo:$MONGO_VERSION AS database
COPY mongo-init.sh /docker-entrypoint-initdb.d
## stage one, build the service
FROM node:20-alpine AS build
ENV NODE_ENV development
WORKDIR /home/node/app
COPY package*.json ./
COPY tsconfig.json ./
COPY lib ./lib
RUN ls -a
RUN yarn install
RUN yarn build
## this is stage two , where the app actually runs
FROM node:20-alpine AS containerize
ENV NODE_ENV $ENV
WORKDIR /home/node/app
COPY package*.json ./
RUN yarn install --frozen-lockfile --production
COPY --from=build /home/node/app/dist .
EXPOSE $PORT
CMD ["node","server/index.js"]

View File

@@ -1,2 +1,2 @@
# grow-api
# @mifi/auth

6
babel.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};

41
docker-compose.dev.yml Normal file
View File

@@ -0,0 +1,41 @@
version: '3.8'
services:
auth-service_mongo:
env_file: .env.dev
container_name: ${CONTAINER_PREFIX}-auth-service_mongo
ports:
- 27017:27017
networks:
- backend
volumes:
- auth-db:/data/db
- auth-db:/data/configdb
restart: unless-stopped
image: mongo:latest
auth-service:
env_file: .env.dev
build:
context: .
args:
- PORT
- ENV
container_name: ${CONTAINER_PREFIX}-auth-service
ports:
- 9001:9001
environment:
- DB_HOST=${CONTAINER_PREFIX}-auth-service_mongo
networks:
- labs-net
- backend
restart: unless-stopped
image: node:20-alpine
depends_on:
- auth-service_mongo
networks:
labs-net:
name: labs-net
volumes:
auth-db:
external: true

View File

@@ -0,0 +1,58 @@
version: '3.8'
services:
auth-service_mongo:
container_name: ${CONTAINER_PREFIX}-auth-service_mongo
env_file:
- staging.env
build:
context: .
target: database
args:
MONGO_VERSION: 4.4
networks:
- auth-backend
volumes:
- 'auth-db:/data/db'
- 'auth-db:/data/configdb'
restart: unless-stopped
image: mongo:4.4
auth-service:
container_name: ${CONTAINER_PREFIX}-auth-service
env_file:
- staging.env
build:
context: .
target: containerize
args:
- PORT
- ENV
environment:
- DB_HOST=${CONTAINER_PREFIX}-auth-service_mongo
labels:
- 'traefik.enable=true'
- 'traefik.docker.network=docknet'
- 'traefik.http.routers.labs-auth.rule=Host(`${HOST}`) && Path(`${ROUTE_PREFIX}`)'
- 'traefik.http.routers.labs-auth.entrypoints=websecure'
- 'traefik.http.routers.labs-auth.tls=true'
- 'traefik.http.routers.labs-auth.tls.certresolver=letsencrypt'
- 'traefik.http.routers.labs-auth.service=labs-auth-service'
- 'traefik.http.services.labs-auth-service.loadbalancer.server.port=${PORT}'
networks:
- auth-backend
- docknet
restart: unless-stopped
image: node:20-alpine
depends_on:
- auth-service_mongo
networks:
auth-backend:
driver: bridge
external: false
docknet:
name: docknet
external: true
volumes:
auth-db:
external: false

View File

@@ -0,0 +1,43 @@
version: '3.8'
services:
auth-service_mongo:
container_name: ${CONTAINER_PREFIX}-auth-service_mongo
env_file:
- staging.env
networks:
- docknet
volumes:
- auth-db:/data
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
restart: unless-stopped
image: mongo:4.4
auth-service:
env_file:
- staging.env
container_name: ${CONTAINER_PREFIX}-auth-service
environment:
- DB_HOST=${CONTAINER_PREFIX}-auth-service_mongo
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.grow.rule=Host(`${HOST}`) && Path(`${ROUTE_PREFIX}`)'
- 'traefik.http.routers.grow.entrypoints=websecure'
- 'traefik.http.routers.grow.tls=true'
- 'traefik.http.routers.grow.tls.certresolver=letsencrypt'
- 'traefik.http.routers.grow.service=grow-service'
- 'traefik.http.services.grow-service.loadbalancer.server.port=${PORT}'
networks:
- docknet
restart: unless-stopped
depends_on:
- auth-service_mongo
image: git.mifi.dev/mifi/mifi/auth:latest
networks:
docknet:
name: docknet
external: true
volumes:
auth-db:
external: false

195
jest.config.ts Normal file
View File

@@ -0,0 +1,195 @@
/*
* For a detailed explanation regarding each configuration property and type check, visit:
* https://jestjs.io/docs/configuration
*/
export default {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
// bail: 0,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/private/var/folders/75/3cyx0pq133n7gk3ysqf0mj4r0000gn/T/jest_dx",
// Automatically clear mock calls, instances, contexts and results before every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// Indicates which provider should be used to instrument code for coverage
// coverageProvider: "babel",
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// The default configuration for fake timers
// fakeTimers: {
// "enableGlobally": false
// },
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "mjs",
// "cjs",
// "jsx",
// "ts",
// "tsx",
// "json",
// "node"
// ],
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
// moduleNameMapper: {},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
// preset: undefined,
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state before every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state and implementation before every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
// roots: [
// "<rootDir>"
// ],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// The test environment that will be used for testing
// testEnvironment: "jest-environment-node",
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
// testMatch: [
// "**/__tests__/**/*.[jt]s?(x)",
// "**/?(*.)+(spec|test).[tj]s?(x)"
// ],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",
// A map from regular expressions to paths to transformers
// transform: undefined,
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/",
// "\\.pnp\\.[^\\/]+$"
// ],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
// verbose: undefined,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
};

View File

@@ -1,16 +0,0 @@
import passport from 'koa-passport';
import Users from 'grow-db/lib/models/users';
import { User } from 'grow-db/lib/schemas/user';
passport.serializeUser((user: User, done) => { done(null, user._id); });
passport.deserializeUser(async (id, done) => {
const user = await Users.findById(id);
if (user) {
done(null, user);
}
done('user not found', null);
});

8
lib/constants/auth.ts Normal file
View File

@@ -0,0 +1,8 @@
export enum Status {
ACTIVE,
BLOCK_HARD,
BLOCK_SOFT,
DELETED,
INACTIVE,
UNVERIFIED,
}

5
lib/constants/db.ts Normal file
View File

@@ -0,0 +1,5 @@
export const DB_HOST = process.env.DB_HOST;
export const DB_PORT = process.env.DB_PORT || 27017;
export const DB_USERNAME = process.env.DB_USERNAME;
export const DB_PASSWORD = process.env.DB_PASSWORD;
export const DB_NAME = process.env.DB_NAME;

16
lib/constants/env.ts Normal file
View File

@@ -0,0 +1,16 @@
export const PACKAGE_NAME = '@mifi/auth';
export const PORT = process.env.PORT || 9000;
export const SESSION_KEY = process.env.SESSION_KEY || 'secret-key';
export const JWT_AUDIENCE = process.env.JWT_AUDIENCE || 'mifi.dev';
export const JWT_ISSUER = process.env.JWT_ISSUER || PACKAGE_NAME;
export const JWT_SECRET = process.env.JWT_SECRET || 'secret';
export const LOGIN_VALID_TIME = process.env.LOGIN_VALID_TIME || '12H'; // ###D|H|M
export const RESET_VALID_MINUTES = process.env.RESET_VALID_MINUTES || 24;
export const DEFAULT_TOKEN_DAYS = process.env.DEFAULT_TOKEN_DAYS || 365;
export const ROUTE_PREFIX = process.env.ROUTE_PREFIX || '/auth';
export const LOGIN_ROUTE = process.env.LOGIN_ROUTE || '/login';
export const RESET_ROUTE = process.env.RESET_ROUTE || '/reset';

12
lib/constants/errors.ts Normal file
View File

@@ -0,0 +1,12 @@
export enum ErrorCodes {
RESET_REQUEST_DATA = 'RESET_REQUEST_DATA',
}
export const ErrorMessages = {
[ErrorCodes.RESET_REQUEST_DATA]: 'A valid username and password must be provided',
};
export const getErrorBody = (code: ErrorCodes) => ({
code,
message: ErrorMessages[code],
});

View File

@@ -1,231 +0,0 @@
// const errors = require('restify-errors');
// const config = require('../config');
// const handlePassportResponse = (req, res, next) => (err, user, info) => {
// if (err) {
// return next(err);
// }
// const isVerifiedUser = user &&
// user.isRegistrationVerified();
// if (user && isVerifiedUser) {
// return res.send({ ...user.toAuthJSON() });
// } else if (user && !isVerifiedUser){
// return res.send({
// registrationSuccess: true,
// nextSteps: 'Check your email for our confirmation email, you will not be able to login without confirming.'
// });
// }
// return res.send(400, info);
// };
// module.exports = function (server, auth) {
// const { passport } = auth;
// /* Local Auth */
// server.post('/auth', (req, res, next) => {
// const { body: { username = null, password = null } = {} } = req;
// if (!username || !password) {
// let errors = {};
// if (!username) {
// errors.username = 'is required';
// }
// if (!password) {
// errors.password = 'is required';
// }
// return res.send(422, { errors });
// }
// const callback = handlePassportResponse(req, res, next);
// return passport.authenticate('local', { session: false }.then(callback)(req, res, next);
// });
// /**
// * SERVICES
// */
// /* Google */
// server.get(
// '/auth/google',
// passport.authenticate('google', { scope: 'profile email', session: false }),
// );
// server.get(
// '/auth/google/callback',
// (req, res, next) => {
// const callback = handlePassportResponse(req, res, next);
// return passport.authenticate(
// 'google',
// { failureRedirect: '/login' },
// callback,
// )(req, res, next);
// },
// );
// /* Facebook */
// server.get(
// '/auth/facebook/login',
// passport.authenticate('facebook', {
// scope: ['email', 'public_profile'],
// session: false,
// }),
// );
// server.get(
// '/auth/facebook/loggedin',
// (req, res, next) => {
// const callback = handlePassportResponse(req, res, next);
// return passport.authenticate(
// 'facebook',
// { failureRedirect: '/login' },
// callback,
// )(req, res, next);
// }
// );
// server.get(
// '/auth/facebook/link',
// auth.secure,
// (req, res, next) => {
// req.user.record.setLinkCheckBit((err, linkCheckBit) => {
// passport.authenticate('facebookLink', {
// scope: ['email', 'public_profile'],
// session: false,
// state: linkCheckbit,
// })(req, res, next);
// });
// },
// );
//
// server.get(
// '/auth/facebook/linked',
// (req, res, next) => {
// const linkCheckBit = req.query.state;
//
// return passport.authenticate(
// 'facebook',
// { failureRedirect: '/profile' },
// (err, profile) => {
// if (err) {
// return next(err);
// }
//
// User.linkFacebookProfile(linkCheckBit, profile, (err, user) => {
// if (err) {
// return next(err);
// }
//
// if (!user) {
// return next(err, false, 'Linking the account to Facebook was unsuccessful, please try again.');
// }
//
// res.send({
// success: true,
// info: 'Facerbook account successfully linked',
// });
// });
// },
// )(req, res, next);
// }
// );
};
import Koa from 'koa';
import Router from 'koa-router';
import { StatusCodes } from 'http-status-codes';
import Users from 'grow-db/lib/models/users';
const handlePassportResponse = (ctx: Koa.Context) => (err, user, info) => {
if (err) {
return next(err);
}
const isVerifiedUser = user &&
user.isRegistrationVerified();
if (user && isVerifiedUser) {
return res.send({ ...user.toAuthJSON() });
} else if (user && !isVerifiedUser){
return res.send({
registrationSuccess: true,
nextSteps: 'Check your email for our confirmation email, you will not be able to login without confirming.'
});
}
return res.send(400, info);
};
const routerOpts: Router.IRouterOptions = {
prefix: '/auth',
};
const router: Router = new Router(routerOpts);
router.get('/', async (ctx: Koa.Context) => {
const data = await Customers.find({}).exec();
ctx.body = { data };
});
router.get('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findById(ctx.params.customer_id).populate('person').exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { data };
});
router.delete('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findByIdAndDelete(ctx.params.customer_id).exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});
router.post('/', async (ctx: Koa.Context) => {
const data = await Customers.create(ctx.body);
data.save();
ctx.body = { success: true, data };
});
router.post('/', async (ctx: Koa.Context) => {
const { body: { username = null, password = null } = {} } = ctx;
if (!username || !password) {
let errors = {};
if (!username) {
errors.username = 'is required';
}
if (!password) {
errors.password = 'is required';
}
ctx.status = StatusCodes.UNPROCESSABLE_ENTITY;
ctx.throw(422, { errors });
}
const callback = handlePassportResponse(req, res, next);
return passport.authenticate('local', { session: false }, callback)(req, res, next);
});
router.patch('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findByIdAndUpdate(ctx.params.customer_id);
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});

View File

@@ -1,11 +0,0 @@
import mongoose from 'mongoose';
const DB_USER = process.env.DB_USER || 'test';
const DB_PASS = process.env.DB_PASSWORD || 'test';
const DB_HOST = process.env.DB_HOST || 'mongodb';
const DB_PORT = process.env.DB_PORT || 27017;
const DB_NAME = process.env.DB_NAME || 'auth';
export const connection = mongoose.connect(
`${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}`
);

5
lib/db/index.ts Normal file
View File

@@ -0,0 +1,5 @@
import mongoose from 'mongoose';
import { DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_USERNAME } from '../constants/db';
export const connection = mongoose.connect(`mongodb://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}`);

146
lib/db/schema/auth.ts Normal file
View File

@@ -0,0 +1,146 @@
import { JwtPayload } from 'jsonwebtoken';
import { InferSchemaType, Model, Schema, StringSchemaDefinition, Types } from 'mongoose';
import { Strategy } from './strategy';
import { STRATEGIES } from '../../constants/strategies';
import { TokenProps, verify as verifyJwt } from '../../utils/jwt';
import { encrypt, verify as verifyPassword } from '../../utils/password';
import { generateLoginToken, generateResetToken } from '../../utils/tokens';
import { getPasswordResetPath } from '../../utils/links';
import { Status } from '../../constants/auth';
export type Auth = {
is2FA?: boolean;
record: StringSchemaDefinition;
username: string;
};
export type AuthPrivate = Auth & {
status: Status;
strategies: Types.ArraySubdocument<Strategy>;
};
export interface AuthMethods {
authenticate(password: string): boolean;
getAuthStrategy(method?: STRATEGIES): Strategy | false;
getResetLink(route: string): Promise<string | undefined>;
getResetToken(): Promise<string | undefined>;
getToken(props?: Omit<TokenProps, 'sub'> | void): string;
isActive(): boolean;
setPassword(password: string): Promise<boolean>;
}
export interface AuthModel extends Model<AuthPrivate, void, AuthMethods> {
authenticate(username: string, password?: string): string | false;
findByUsername(username: string): Promise<AuthModel & AuthPrivate>;
isUsernameAvailable(username: string): Promise<boolean>;
findUserForReset(strategy: STRATEGIES, token: string): Promise<Strategy | undefined>;
resetPassword(token: string, password: string): Promise<string | false>;
}
export const AuthSchema = new Schema<AuthPrivate, AuthModel, AuthMethods>(
{
is2FA: { type: Boolean, default: false },
record: { type: Types.ObjectId },
strategies: { type: Array<Strategy>, required: true },
status: { type: Number, enum: Object.values(Status), default: Status.UNVERIFIED },
username: { type: String, required: true, unique: true },
},
{
minimize: true,
timestamps: true,
},
);
AuthSchema.methods = {
authenticate(password: string) {
const strategy = this.getAuthStrategy(STRATEGIES.LOCAL);
return !!strategy && verifyPassword(password, strategy.key);
},
getAuthStrategy(method = STRATEGIES.LOCAL) {
return this.strategies.filter((strategy: Strategy) => strategy.method === method).pop() || false;
},
getToken(props = {}) {
return generateLoginToken(this._id, this.status);
},
async getResetLink(route) {
const token = await this.getResetToken();
if (token) {
const resetUrl = getPasswordResetPath(token);
console.log('[sendPasswordReset] resetUrl:', resetUrl);
return resetUrl;
}
},
async getResetToken() {
const { key, token } = generateResetToken(this._id);
this.resetCheckBit = key;
await this.save().catch(() => undefined);
return token;
},
isActive() {
return this.status === Status.ACTIVE;
},
async setPassword(password) {
const key = encrypt(password);
const hasLocalStrategy = !!this.getAuthStrategy(STRATEGIES.LOCAL);
const strategy = {
key,
method: STRATEGIES.LOCAL,
resetToken: undefined,
};
if (hasLocalStrategy) {
await this.model('User')
.findOneAndUpdate(
{ _id: this._id, 'strategies.method': STRATEGIES.LOCAL },
{ $set: { 'strategies.$': strategy } },
{ upsert: true },
)
.catch();
return true;
}
this.credentials.push(strategy);
await this.save().catch(() => false);
return true;
},
};
AuthSchema.statics = {
authenticate: async function (username, password) {
const auth = await this.findByUsername(username);
if (auth && auth.authenticate(password)) {
return auth.record;
}
return false;
},
async findByUsername(username) {
return this.findOne({ username });
},
async isUsernameAvailable(username) {
return !this.findByUsername(username);
},
async resetPassword(token, password) {
const decoded = verifyJwt(token);
const { sub, key } = decoded as JwtPayload;
const auth = await this.findOne({
_id: sub,
'strategies.resetToken': key,
}).catch();
if (auth) {
await auth.setPassword(password).catch();
return auth.getToken();
}
return false;
},
};
export type AuthSchema = InferSchemaType<typeof AuthSchema>;

View File

@@ -1,5 +1,5 @@
import { InferSchemaType, Schema, Types } from 'mongoose';
import { STRATEGIES } from '../constants/strategies';
import { STRATEGIES } from '../../constants/strategies';
export const Strategy = new Schema(
{
@@ -17,8 +17,8 @@ export const Strategy = new Schema(
forceReset: { type: Boolean },
},
{
minimize: true,
timestamps: true,
minimize: true,
timestamps: true,
},
);

View File

@@ -1,13 +0,0 @@
import { StatusCodes } from "http-status-codes";
import { Context, Next } from "koa";
export const errorHandler = async (ctx: Context, next: Next) => {
try {
await next();
} catch (error: any) {
ctx.status = error.statusCode || error.status || StatusCodes.INTERNAL_SERVER_ERROR;
error.status = ctx.status;
ctx.body = { error };
ctx.app.emit('error', error, ctx);
}
};

View File

@@ -1,134 +0,0 @@
import { JwtPayload } from 'jsonwebtoken';
import { Document, InferSchemaType, Model, Schema, StringSchemaDefinition, Types } from 'mongoose';
import { Strategy } from './strategy';
import { STRATEGIES } from '../constants/strategies';
import { TokenProps, sign, verify as verifyJwt } from '../utils/jwt';
import { encrypt, verify as verifyPassword } from '../utils/password';
import { generateResetToken } from '../utils/tokens';
export type Auth = {
is2FA?: boolean;
record: StringSchemaDefinition;
username: string;
}
export type AuthPrivate = Auth & {
strategies: Types.ArraySubdocument<Strategy>;
}
export interface AuthMethods {
authenticate(password: string): boolean;
getAuthStrategy(method?: STRATEGIES): Strategy | false;
getResetLink(route: string): Promise<string | undefined>;
getResetToken(): Promise<string | undefined>;
getToken(props?: Omit<TokenProps, 'sub'>): string;
setPassword(password: string): Promise<boolean>;
}
export interface AuthModel extends Model<AuthPrivate, {}, AuthMethods> {
authenticate(password: any): boolean;
findByUsername(username: string): Promise<AuthModel & AuthPrivate>;
isUsernameAvailable(username: string): Promise<boolean>;
findUserForReset(strategy: STRATEGIES, token: string): Promise<Strategy | undefined>;
resetPassword(token: string, password: string): Promise<boolean>;
}
export const AuthSchema = new Schema<AuthPrivate, AuthModel, AuthMethods>(
{
is2FA: { type: Boolean, default: false },
record: { type: Types.ObjectId },
strategies: { type: Types.ArraySubdocument<Strategy>, required: true },
username: { type: String, required: true, unique: true },
},
{
minimize: true,
timestamps: true,
},
);
AuthSchema.methods = {
authenticate: function(password: string) {
const strategy = this.getAuthStrategy(STRATEGIES.LOCAL);
return !!strategy && verifyPassword(password, strategy.key);
},
getAuthStrategy: function(method = STRATEGIES.LOCAL) {
return this.strategies.filter((strategy: Strategy) => strategy.method === method).pop() || false;
},
getToken: function(props = {}) {
return sign({
sub: this._id,
...props,
});
},
getResetLink: async function (route) {
const resetToken = await this.getResetToken();
if (resetToken) {
let resetRoute = route;
resetRoute = resetRoute.replace(':user_id', this._id);
resetRoute = resetRoute.replace(':reset_token?', resetToken);
const resetUrl = `${process.env.URL}${resetRoute}`;
console.log('[sendPasswordReset] resetUrl:', resetUrl);
return resetUrl;
}
},
getResetToken: async function () {
const { key, token } = generateResetToken(this._id);
this.resetCheckBit = key;
await this.save().catch(() => undefined);
return token;
},
setPassword: async function (password) {
const key = encrypt(password);
const hasLocalStrategy = !!this.getAuthStrategy(STRATEGIES.LOCAL);
const strategy = {
key,
method: STRATEGIES.LOCAL,
resetToken: undefined,
};
if (hasLocalStrategy) {
await this.model('User').findOneAndUpdate(
{ _id: this._id, 'strategies.method': STRATEGIES.LOCAL },
{ $set: { 'strategies.$': strategy } },
{ upsert: true },
).catch();
return true;
}
this.credentials.push(strategy);
await this.save().catch(() => false);
return true;
},
};
AuthSchema.statics = {
// authenticateAndGetRecordLocator: async function (username, password) {
// const auth = await this.findByUserName(username);
// if (auth && auth.authenticate(password)) {
// return auth?.record;
// }
// return false;
// },
findByUsername: async function (username) {
return this.findOne({ username });
},
isUsernameAvailable: async function (username) {
return !!!this.findByUsername(username);
},
resetPassword: async function (token, password) {
const decoded = verifyJwt(token);
const { sub, key } = decoded as JwtPayload;
const auth = await this.findOne({ _id: sub, 'strategies.resetToken': key }).catch();
return !!auth && auth.setPassword(password);
},
};
export type AuthSchema = InferSchemaType<typeof AuthSchema>;

View File

@@ -1,12 +0,0 @@
import dotenv from 'dotenv';
dotenv.config();
import app from './app';
import { connection } from './database/database.connection';
const PORT: number = Number(process.env.PORT) || 9000;
connection.then(
() => app.listen(PORT),
(err) => console.error('ERROR!', err),
);

View File

@@ -1,27 +1,32 @@
import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
import bodyparser from 'koa-bodyparser';
import cookie from 'koa-cookie';
import passport from 'koa-passport';
import session from 'koa-session';
import passport from './passport';
import { performanceLogger, perfromanceTimer } from './middleware/performance';
import { errorHandler } from './middleware/errorHandler';
import { authRouter } from './controllers/auth';
import { SESSION_KEY } from '../constants/env';
const app: Koa = new Koa();
app.use(errorHandler);
app.use(perfromanceTimer);
app.use(performanceLogger);
app.use(bodyParser());
app.use(bodyparser());
app.use(cookie());
app.keys = [process.env.SESSION_KEYS as string];
app.keys = [SESSION_KEY];
app.use(session({}, app));
app.use(passport.initialize())
app.use(passport.session())
app.use(passport.initialize());
app.use(passport.session());
app.use(authRouter.routes());
app.use(authRouter.allowedMethods());
// Application error logging.
app.on('error', console.error);
export default app;
export default app;

View File

@@ -0,0 +1,58 @@
import Koa from 'koa';
import Router from 'koa-router';
import { StatusCodes } from 'http-status-codes';
import { ROUTE_PREFIX as prefix, RESET_ROUTE } from '../../constants/env';
import Auth from '../../db/model/auth';
import { sign } from '../../utils/jwt';
import passport from '../passport';
import { ErrorCodes, getErrorBody } from '../../constants/errors';
import { authenticated } from '../middleware/authenication';
const routerOpts: Router.IRouterOptions = { prefix };
const router: Router = new Router(routerOpts);
router.get('/info', (ctx) => {
ctx.body = {
service: process.env.SERVICE_NAME,
};
});
router.post('/', async (ctx) => {
const data = (await Auth.create(ctx.body)).save();
ctx.body = { success: true, data: { ...data, strategies: undefined } };
});
router.post('/login', async (ctx, next) => {
return passport.authenticate('local', (err, user) => {
if (user === false) {
ctx.body = { token: null };
ctx.throw(StatusCodes.UNAUTHORIZED);
}
ctx.body = { token: sign(user) };
return ctx.login(user);
})(ctx, next);
});
router.post(process.env.RESET_ROUTE || RESET_ROUTE, async (ctx, next) => {
const { token = null, password = null } = ctx.request.body as { token?: string; password?: string };
if (token && password) {
const loginToken = await Auth.resetPassword(token, password).catch();
ctx.body({ token: loginToken });
next();
}
ctx.body = { success: false, ...getErrorBody(ErrorCodes.RESET_REQUEST_DATA) };
});
router.patch('/:record', authenticated(), (ctx: Koa.Context) => {
if (ctx.user !== ctx.param.record) {
ctx.throw(StatusCodes.UNAUTHORIZED);
}
const data = Auth.findOneAndUpdate({ record: ctx.params.record });
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});
export { router as authRouter };

11
lib/server/index.ts Normal file
View File

@@ -0,0 +1,11 @@
import app from './app';
import { connection } from '../db';
import { PORT } from '../constants/env';
connection.then(
() => {
app.listen(PORT);
console.debug('Server up and listening', { env: process.env });
},
(err) => console.error('Could not reach database', { err, env: process.env }),
);

View File

@@ -0,0 +1,12 @@
import { Middleware } from 'koa';
import { LOGIN_ROUTE } from '../../constants/env';
export const authenticated = (): Middleware => {
return (ctx, next) => {
if (ctx.isAuthenticated()) {
return next();
} else {
ctx.redirect(process.env.LOGIN_ROUTE || LOGIN_ROUTE);
}
};
};

View File

@@ -1,5 +1,5 @@
import { StatusCodes } from "http-status-codes";
import { Context, Next } from "koa";
import { StatusCodes } from 'http-status-codes';
import { Context, Next } from 'koa';
export const errorHandler = async (ctx: Context, next: Next) => {
try {

View File

@@ -1,13 +1,12 @@
import { Next } from 'koa';
import { KoaContext } from '../types/KoaContext';
import { Context, Next } from 'koa';
export const performanceLogger = async (ctx: KoaContext, next: Next) => {
export const performanceLogger = async (ctx: Context, next: Next) => {
await next();
const rt = ctx.response.get('X-Response-Time');
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
};
export const perfromanceTimer = async (ctx: KoaContext, next: Next) => {
export const perfromanceTimer = async (ctx: Context, next: Next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;

View File

@@ -0,0 +1,23 @@
import passport from 'koa-passport';
import Auth from '../../db/model/auth';
import { Auth as AuthRecord } from '../../db/schema/auth';
import LocalStrategy from './strategies/local';
import JwtStrategy from './strategies/jwt';
passport.serializeUser((user, done) => done(null, (user as AuthRecord).record));
passport.deserializeUser(async (id, done) => {
const user = await Auth.findOne({ record: id });
if (user) {
done(null, user);
}
done('user not found', null);
});
passport.use(LocalStrategy);
passport.use(JwtStrategy);
export default passport;

View File

@@ -0,0 +1,22 @@
// eslint-disable-next-line import/named
import { ExtractJwt, Strategy as JwtStrategy } from 'passport-jwt';
import Auth from '../../../db/model/auth';
import { JWT_SECRET } from '../../../constants/env';
const opts = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: JWT_SECRET,
issuer: process.env.JWT_ISSUER,
audience: process.env.JWT_AUDIENCE,
};
export default new JwtStrategy(opts, async (jwt_payload, done) => {
const auth = await Auth.findOne({ record: jwt_payload.sub }).catch();
if (auth) {
return done(null, auth);
}
return done(null, false);
});

View File

@@ -0,0 +1,17 @@
// eslint-disable-next-line import/named
import { Strategy as LocalStrategy } from 'passport-local';
import Auth from '../../../db/model/auth';
export default new LocalStrategy(async (username: string, password: string, done: any) => {
const user = await Auth.findOne({
where: {
username,
},
}).catch();
if (user && user.authenticate(password)) {
done(null, user);
} else {
done(null, false);
}
});

View File

@@ -1,20 +0,0 @@
import passport from 'koa-passport';
import { Strategy } from 'passport-local';
import bcrypt from 'bcrypt';
import Auth from '../model/auth';
import { AuthSchema } from '../schema/auth';
export const LocalStrategy = passport.use(new Strategy(async (username, password, done) => {
const user = await Auth.findOne({
where: {
username,
}
}).catch();
if (user && user.authenticate(password)) {
done(null, user);
} else {
done(null, false);
}
}
));

View File

@@ -1,12 +1,12 @@
import Auth from '../model/auth';
import { AuthDocument, AuthModel, AuthPrivate } from '../schema/auth';
import Auth from '../db/model/auth';
import { AuthModel, AuthPrivate } from '../db/schema/auth';
import { sign } from './jwt';
export const getAuthenticationBundle = async (username: string, password: string) => {
const auth = await Auth.findByUsername(username).catch();
const isAuthenticated = !!auth && (auth as AuthModel).authenticate(password);
const token = isAuthenticated ? (auth as AuthModel).getToken() : sign();
const record = isAuthenticated ? (auth as AuthPrivate).record : null;
const isAuthenticated = !!auth && (<AuthModel>auth).authenticate(password);
const record = isAuthenticated ? <string>(<AuthPrivate>auth).record : null;
const token = sign(record || undefined);
return {
record,
token,

View File

@@ -1,5 +1,5 @@
import jwt, { JwtPayload } from 'jsonwebtoken';
import jwt from 'jsonwebtoken';
import { JWT_AUDIENCE, JWT_ISSUER, JWT_SECRET } from '../constants/env';
export interface TokenProps {
aud?: string;
exp?: number | Date;
@@ -12,20 +12,24 @@ export type SignProps = string | TokenProps | void;
export const sign = (props: SignProps) => {
const today = new Date();
const { sub = null, ...rest }: TokenProps = typeof props === 'string' || typeof props === 'undefined' ? { sub: props || null } : props;
let exp = rest.exp;
const { sub = null, ...rest }: TokenProps =
typeof props === 'string' || typeof props === 'undefined' ? { sub: props || null } : props;
let { exp } = rest;
if (!exp) {
exp = new Date(today);
exp.setDate(today.getDate() + parseInt(process.env.JWT_DAYS_VALID as string));
exp = exp.getTime() / 1000;
}
return jwt.sign({
aud: rest.aud || process.env.JWT_AUDIENCE,
exp,
iat: today.getTime(),
iss: rest.iss || process.env.JWT_ISSUER,
sub,
}, process.env.JWT_SECRET || 'secret');
return jwt.sign(
{
exp,
sub,
aud: rest.aud || JWT_AUDIENCE,
iat: today.getTime(),
iss: rest.iss || JWT_ISSUER,
},
JWT_SECRET,
);
};
export const verify = (token: string) => jwt.verify(token, process.env.JWT_SECRET || 'secret');
export const verify = (token: string) => jwt.verify(token, JWT_SECRET);

3
lib/utils/links.ts Normal file
View File

@@ -0,0 +1,3 @@
import { RESET_ROUTE, ROUTE_PREFIX } from '../constants/env';
export const getPasswordResetPath = (token: string) => `${ROUTE_PREFIX}${RESET_ROUTE}?t=${token}`;

View File

@@ -1,12 +1,12 @@
import crypto from 'crypto';
import { pbkdf2Sync, randomBytes } from 'crypto';
export const encrypt = (password: string) => {
const salt = crypto.randomBytes(16).toString('hex');
const hash = crypto.pbkdf2Sync(password, salt, 10000, 512, 'sha512').toString('hex');
const salt = randomBytes(16).toString('hex');
const hash = pbkdf2Sync(password, salt, 10000, 512, 'sha512').toString('hex');
return `${salt}:${hash}`;
};
export const verify = (test: string, secret: string) => {
const [salt, hash] = secret.split(':');
return crypto.pbkdf2Sync(test, salt, 10000, 512, 'sha512').toString('hex') === hash;
return pbkdf2Sync(test, salt, 10000, 512, 'sha512').toString('hex') === hash;
};

View File

@@ -1,13 +1,34 @@
import crypto from 'crypto';
import { sign } from "./jwt";
import { sign } from './jwt';
import { LOGIN_VALID_TIME, RESET_VALID_MINUTES } from '../constants/env';
import { Status } from '../constants/auth';
const parseLoginValid = () => {
const [number, unit] = process.env.LOGIN_VALID_TIME || LOGIN_VALID_TIME;
return [
unit === 'd' ? parseInt(number) : 1,
unit === 'h' ? parseInt(number) : (unit === 'm' && 1) || 24,
unit === 'm' ? parseInt(number) : 60,
];
};
export const generateLoginToken = (sub: string, status: Status) => {
const [days, hours, mins] = parseLoginValid();
return sign({
sub,
status,
exp: Date.now() + days * hours * mins * 60 * 1000,
});
};
export const generateResetToken = (sub: string) => {
const hoursValid = <number>(process.env.RESET_VALID_HOURS || RESET_VALID_MINUTES);
const key = crypto.randomBytes(16).toString('hex');
const token = sign({
sub,
key,
exp: (Date.now() + (24 * 60 * 60 * 1000)),
exp: Date.now() + hoursValid * 60 * 60 * 1000,
});
return { key, token };
};
};

14
mongo-init.sh Normal file
View File

@@ -0,0 +1,14 @@
set -e
mongo <<EOF
use $MONGO_INITDB_DATABASE
db.createUser({
user: '$DB_USERNAME',
pwd: '$DB_PASSWORD',
roles: [{
role: 'readWrite',
db: '$MONGO_INITDB_DATABASE'
}]
})
EOF

View File

@@ -1,5 +0,0 @@
{
"watch": ["src"],
"exec": "yarn run serve",
"ext": "ts"
}

View File

@@ -1,21 +1,26 @@
{
"name": "@mifi/grow-api",
"version": "0.0.1",
"main": "server.js",
"name": "@mifi/auth",
"version": "0.0.38",
"author": "mifi (Mike Fitzpatrick)",
"license": "MIT",
"scripts": {
"build": "tsc",
"lint": "tslint --project tsconfig.json --format stylish",
"prettier:fix": "prettier-eslint --eslint-config-path ./.eslintrc.js --write '**/*.ts'",
"serve": "ts-node src/server.ts",
"start": "nodemon"
"build:production": "tsc -p .",
"format": "prettier:fix && lint:fix",
"lint": "eslint --ext .ts,.tsx lib/",
"lint:fix": "eslint --fix --ext .ts,.tsx lib/",
"prettier": "prettier --check 'lib/**/*.ts'",
"prettier:fix": "prettier --write 'lib/**/*.ts'",
"serve": "node dist/lib/server/index.js",
"start": "nodemon",
"test": "jest --passWithNoTests"
},
"devDependencies": {
"@babel/core": "^7.21.8",
"@babel/preset-env": "^7.21.5",
"@babel/preset-typescript": "^7.21.5",
"@tsconfig/node16": "^1.0.3",
"@types/crypto-js": "^4.1.1",
"@types/dotenv": "^8.2.0",
"@types/http-status-codes": "^1.2.0",
"@types/jest": "^29.5.1",
"@types/jsonwebtoken": "^9.0.1",
"@types/koa": "^2.13.5",
"@types/koa-bodyparser": "^4.3.10",
@@ -24,7 +29,6 @@
"@types/koa-router": "^7.4.4",
"@types/koa-session": "^5.10.6",
"@types/luxon": "^3.2.0",
"@types/mongoose": "^5.11.97",
"@types/node": "^18.14.0",
"@types/passport": "^1.0.12",
"@types/passport-facebook": "^2.1.11",
@@ -32,20 +36,27 @@
"@types/passport-google-oauth": "^1.0.42",
"@types/passport-jwt": "^3.0.8",
"@types/passport-local": "^1.0.35",
"jest": "^29.4.2",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/parser": "^5.59.2",
"babel-jest": "^29.5.0",
"eslint": "^8.39.0",
"eslint-config-prettier": "^8.8.0",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.0.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.0.0",
"jest": "^29.5.0",
"nodemon": "^2.0.20",
"prettier": "^2.8.4",
"prettier-eslint": "^15.0.1",
"prettier-eslint-cli": "^7.1.0",
"reflect-metadata": "^0.1.13",
"ts-node": "^10.9.1",
"tslint": "^6.1.3",
"tslint-config-airbnb": "^5.11.2",
"typescript": "^4.9.5"
},
"dependencies": {
"@mifi/grow-db": "0.0.1",
"crypto": "^1.0.1",
"@simplewebauthn/server": "^7.2.0",
"dotenv": "^16.0.3",
"http-status-codes": "^2.2.0",
"jsonwebtoken": "^9.0.0",
@@ -61,12 +72,13 @@
"passport-facebook": "^3.0.0",
"passport-fido2-webauthn": "^0.1.0",
"passport-google-oauth": "^2.0.0",
"passport-http-bearer": "^1.0.1",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0"
},
"description": "",
"repository": {
"type": "git",
"url": "https://git.mifi.dev/mifi/grow-api.git"
"url": "https://git.mifi.dev/mifi/auth.git"
}
}

View File

@@ -1,27 +0,0 @@
import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
import cookie from 'koa-cookie';
import passport from 'koa-passport';
import session from 'koa-session';
import { performanceLogger, perfromanceTimer } from '../middleware/performance';
import { errorHandler } from '../middleware/errorHandler';
const app: Koa = new Koa();
app.use(errorHandler);
app.use(perfromanceTimer);
app.use(performanceLogger);
app.use(bodyParser());
app.use(cookie());
app.keys = [process.env.SESSION_KEYS as string];
app.use(session({}, app));
app.use(passport.initialize())
app.use(passport.session())
// Application error logging.
app.on('error', console.error);
export default app;

View File

@@ -1,16 +0,0 @@
import passport from 'koa-passport';
import Users from 'grow-db/lib/models/users';
import { User } from 'grow-db/lib/schemas/user';
passport.serializeUser((user: User, done) => { done(null, user._id); });
passport.deserializeUser(async (id, done) => {
const user = await Users.findById(id);
if (user) {
done(null, user);
}
done('user not found', null);
});

View File

@@ -1,231 +0,0 @@
// const errors = require('restify-errors');
// const config = require('../config');
// const handlePassportResponse = (req, res, next) => (err, user, info) => {
// if (err) {
// return next(err);
// }
// const isVerifiedUser = user &&
// user.isRegistrationVerified();
// if (user && isVerifiedUser) {
// return res.send({ ...user.toAuthJSON() });
// } else if (user && !isVerifiedUser){
// return res.send({
// registrationSuccess: true,
// nextSteps: 'Check your email for our confirmation email, you will not be able to login without confirming.'
// });
// }
// return res.send(400, info);
// };
// module.exports = function (server, auth) {
// const { passport } = auth;
// /* Local Auth */
// server.post('/auth', (req, res, next) => {
// const { body: { username = null, password = null } = {} } = req;
// if (!username || !password) {
// let errors = {};
// if (!username) {
// errors.username = 'is required';
// }
// if (!password) {
// errors.password = 'is required';
// }
// return res.send(422, { errors });
// }
// const callback = handlePassportResponse(req, res, next);
// return passport.authenticate('local', { session: false }.then(callback)(req, res, next);
// });
// /**
// * SERVICES
// */
// /* Google */
// server.get(
// '/auth/google',
// passport.authenticate('google', { scope: 'profile email', session: false }),
// );
// server.get(
// '/auth/google/callback',
// (req, res, next) => {
// const callback = handlePassportResponse(req, res, next);
// return passport.authenticate(
// 'google',
// { failureRedirect: '/login' },
// callback,
// )(req, res, next);
// },
// );
// /* Facebook */
// server.get(
// '/auth/facebook/login',
// passport.authenticate('facebook', {
// scope: ['email', 'public_profile'],
// session: false,
// }),
// );
// server.get(
// '/auth/facebook/loggedin',
// (req, res, next) => {
// const callback = handlePassportResponse(req, res, next);
// return passport.authenticate(
// 'facebook',
// { failureRedirect: '/login' },
// callback,
// )(req, res, next);
// }
// );
// server.get(
// '/auth/facebook/link',
// auth.secure,
// (req, res, next) => {
// req.user.record.setLinkCheckBit((err, linkCheckBit) => {
// passport.authenticate('facebookLink', {
// scope: ['email', 'public_profile'],
// session: false,
// state: linkCheckbit,
// })(req, res, next);
// });
// },
// );
//
// server.get(
// '/auth/facebook/linked',
// (req, res, next) => {
// const linkCheckBit = req.query.state;
//
// return passport.authenticate(
// 'facebook',
// { failureRedirect: '/profile' },
// (err, profile) => {
// if (err) {
// return next(err);
// }
//
// User.linkFacebookProfile(linkCheckBit, profile, (err, user) => {
// if (err) {
// return next(err);
// }
//
// if (!user) {
// return next(err, false, 'Linking the account to Facebook was unsuccessful, please try again.');
// }
//
// res.send({
// success: true,
// info: 'Facerbook account successfully linked',
// });
// });
// },
// )(req, res, next);
// }
// );
};
import Koa from 'koa';
import Router from 'koa-router';
import { StatusCodes } from 'http-status-codes';
import Users from 'grow-db/lib/models/users';
const handlePassportResponse = (ctx: Koa.Context) => (err, user, info) => {
if (err) {
return next(err);
}
const isVerifiedUser = user &&
user.isRegistrationVerified();
if (user && isVerifiedUser) {
return res.send({ ...user.toAuthJSON() });
} else if (user && !isVerifiedUser){
return res.send({
registrationSuccess: true,
nextSteps: 'Check your email for our confirmation email, you will not be able to login without confirming.'
});
}
return res.send(400, info);
};
const routerOpts: Router.IRouterOptions = {
prefix: '/auth',
};
const router: Router = new Router(routerOpts);
router.get('/', async (ctx: Koa.Context) => {
const data = await Customers.find({}).exec();
ctx.body = { data };
});
router.get('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findById(ctx.params.customer_id).populate('person').exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { data };
});
router.delete('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findByIdAndDelete(ctx.params.customer_id).exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});
router.post('/', async (ctx: Koa.Context) => {
const data = await Customers.create(ctx.body);
data.save();
ctx.body = { success: true, data };
});
router.post('/', async (ctx: Koa.Context) => {
const { body: { username = null, password = null } = {} } = ctx;
if (!username || !password) {
let errors = {};
if (!username) {
errors.username = 'is required';
}
if (!password) {
errors.password = 'is required';
}
ctx.status = StatusCodes.UNPROCESSABLE_ENTITY;
ctx.throw(422, { errors });
}
const callback = handlePassportResponse(req, res, next);
return passport.authenticate('local', { session: false }, callback)(req, res, next);
});
router.patch('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findByIdAndUpdate(ctx.params.customer_id);
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});

View File

@@ -1,47 +0,0 @@
import Koa from 'koa';
import Router from 'koa-router';
import { StatusCodes } from 'http-status-codes';
import Customers from 'grow-db/lib/models/customers';
const routerOpts: Router.IRouterOptions = {
prefix: '/customers',
};
const router: Router = new Router(routerOpts);
router.get('/', async (ctx: Koa.Context) => {
const data = await Customers.find({}).exec();
ctx.body = { data };
});
router.get('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findById(ctx.params.customer_id).populate('person').exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { data };
});
router.delete('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findByIdAndDelete(ctx.params.customer_id).exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});
router.post('/', async (ctx: Koa.Context) => {
const data = await Customers.create(ctx.body);
data.save();
ctx.body = { success: true, data };
});
router.patch('/:customer_id', async (ctx: Koa.Context) => {
const data = await Customers.findByIdAndUpdate(ctx.params.customer_id);
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});

View File

@@ -1,17 +0,0 @@
import Koa from 'koa';
import Router from 'koa-router';
import { StatusCodes } from 'http-status-codes';
import Users from 'grow-db/lib/models/users';
const routerOpts: Router.IRouterOptions = {
prefix: '/login',
};
const router: Router = new Router(routerOpts);
router.post('/', async (ctx: Koa.Context) => {
const data = await Users.create(ctx.body);
data.save();
ctx.body = { success: true, data };
});

View File

@@ -1,46 +0,0 @@
import Koa from 'koa';
import Router from 'koa-router';
import { StatusCodes } from 'http-status-codes';
import People from 'grow-db/lib/models/people';
const routerOpts: Router.IRouterOptions = {
prefix: '/people',
};
const router: Router = new Router(routerOpts);
router.get('/', async (ctx: Koa.Context) => {
const data = await People.find({}).exec();
ctx.body = { data };
});
router.get('/:person_id', async (ctx: Koa.Context) => {
const data = await People.findById(ctx.params.person_id).populate('person').exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { data };
});
router.delete('/:person_id', async (ctx: Koa.Context) => {
const data = await People.findByIdAndDelete(ctx.params.person_id).exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});
router.post('/', async (ctx: Koa.Context) => {
const data = await People.create(ctx.body);
data.save();
ctx.body = { success: true, data };
});
router.patch('/:person_id', async (ctx: Koa.Context) => {
const data = await People.findByIdAndUpdate(ctx.params.person_id);
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});

View File

@@ -1,68 +0,0 @@
const errors = require('restify-errors');
const jwt = require('jsonwebtoken');
const config = require('../config');
const User = require('../models/user');
const {
api: { url },
security: { reset: { route, tokenPlaceholder } },
} = config;
const routes = {
resetWithToken: `${route}/${tokenPlaceholder}([A-Za-z0-9_]+\.{3})`,
getTestToken: `${route}/generate`,
};
module.exports = function (server, auth) {
server.get(routes.getTestToken, auth.secure, function (req, res, next) {
const { record: user } = req.user;
const resetToken = user.generateResetToken();
const resetUrl = `${url}${route}/${resetToken}`;
res.send({ resetToken, resetUrl });
next();
});
server.post(routes.resetWithToken, auth.bypass, function (req, res, next) {
const { reset_token } = req.params;
const { password } = req.body;
if (!reset_token) {
return next(
new errors.InvalidContentError('A reset token was not provided.'),
);
}
if (!password) {
return next(
new errors.InvalidContentError('Password cannot be empty.'),
);
}
User.verifyTokenAndResetPassword(reset_token, password, (err, user, info) => {
if (err) {
console.error(err);
return next(
new errors.InvalidContentError(err),
);
}
if (!user) {
console.error(err);
res.send({
success: false,
info: 'Password reset failed. ' + info,
});
return next();
}
res.send({
success: true,
info: 'Password reset successful.',
...user.toAuthJSON()
});
next();
});
});
};

View File

@@ -1,106 +0,0 @@
const errors = require('restify-errors');
const User = require('../models/user');
module.exports = function (server, auth) {
const { passport } = auth;
server.post('/signup', auth.basic, (req, res, next) => {
const { body: { user = null } = {} } = req;
let errors = {};
let errorCount = 0;
if (!user) {
errors.user = 'is required - can\'t make something from nothing...';
errorCount++;
}
if (errorCount) {
return res.send(422, { errors });
}
User.register(user, (err, user, info) => {
if (err) {
next(err);
}
if (info) {
res.send(200, {
success: false,
nextSteps: 'Please fix the problems indicated and try again.',
...info
});
return next();
}
res.send(200, {
success: true,
nextSteps: 'Check your email for our confirmation email, you will not be able to login without confirming.',
});
next();
});
});
server.get('/signup/validate/email/:email', auth.basic, (req, res, next) => {
const email = decodeURI(req.params.email);
User.findOne({ email }, (err, user) => {
if (err) {
return next(err);
}
res.send(200, { available: !!!user });
next();
});
});
server.get('/signup/validate/nom/:nom_de_bid', auth.basic, (req, res, next) => {
const nomDeBid = decodeURI(req.params.nom_de_bid);
User.findOne({ nomDeBid }, (err, user) => {
if (err) {
return next(err);
}
res.send(200, { available: !!!user });
next();
});
});
server.post('/signup/verify/resend', auth.basic, (req, res, next) => {
const { body: { email = null } = {} } = req;
User.resendVerificationEmail(email, (err, user, info) => {
if (err) {
next(err);
}
if (!user) {
res.send(200, {
success: false,
nextSteps: 'There was no user located with the email address provided. Please try again.',
});
return next();
}
if (user && info.success) {
res.send(200, {
success: true,
nextSteps: 'Check your email for our confirmation email, you will not be able to login without confirming.',
});
return next();
}
res.send(200, {
success: false,
nextSteps: 'There was a problem resending the verification email. Please try again later.',
});
next();
});
});
};

View File

@@ -1,49 +0,0 @@
import { Context } from 'koa';
import Router from 'koa-router';
import { } from 'koa-bodyparser';
import { StatusCodes } from 'http-status-codes';
import Strains from 'grow-db/lib/models/strains';
import { Strain } from 'grow-db/lib/schemas/strain';
const routerOpts: Router.IRouterOptions = {
prefix: '/strains',
};
const router: Router = new Router(routerOpts);
router.get('/', async (ctx: Context) => {
const data = await Strains.find({}).exec();
ctx.body = { data };
});
router.get('/:strain_id', async (ctx) => {
const data = await Strains.findById(ctx.params.strain_id).populate('person').exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { data };
});
router.delete('/:strain_id', async (ctx: Context) => {
const data = await Strains.findByIdAndDelete(ctx.params.strain_id).exec();
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});
router.post('/', async (ctx: Context) => {
const data = await Strains.create(ctx.request.body);
data.save();
ctx.body = { success: true, data };
});
router.patch('/:strain_id', async (ctx) => {
const data = await Strains.findByIdAndUpdate(ctx.params.strain_id, <Strain>ctx.request.body, { lean: true, returnDocument: 'after' });
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});

View File

@@ -1,5 +0,0 @@
import mongoose from 'mongoose';
export const connection = mongoose.connect(
`${process.env.DB_USER}:${process.env.DB_PASSWORD}@mongodb:27017/${process.env.DB_NAME}`
);

View File

@@ -1,15 +0,0 @@
import { Next } from 'koa';
import { KoaContext } from '../types/KoaContext';
export const performanceLogger = async (ctx: KoaContext, next: Next) => {
await next();
const rt = ctx.response.get('X-Response-Time');
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
};
export const perfromanceTimer = async (ctx: KoaContext, next: Next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
};

View File

@@ -1,12 +0,0 @@
import dotenv from 'dotenv';
dotenv.config();
import app from './app/app';
import { connection } from './database/database.connection';
const PORT: number = Number(process.env.PORT) || 9000;
connection.then(
() => app.listen(PORT),
(err) => console.error('ERROR!', err),
);

View File

@@ -1,12 +0,0 @@
import { Context, Request } from 'koa';
interface KoaRequest<RequestBody = any> extends Request {
body?: RequestBody;
}
export interface KoaContext<RequestBody = any, ResponseBody = any> extends Context {
request: KoaRequest<RequestBody>;
body: ResponseBody;
}
export interface KoaResponseContext<ResponseBody> extends KoaContext<any, ResponseBody> {};

View File

@@ -6,7 +6,7 @@
"emitDecoratorMetadata": true,
"noImplicitAny": true,
"outDir": "./dist/",
"rootDirs": ["src", "../"],
"rootDirs": ["lib"],
"sourceMap": true
}
}

View File

@@ -1,6 +0,0 @@
{
"extends": "tslint-config-airbnb",
"rules": {
"import-name": false
}
}

5267
yarn.lock

File diff suppressed because it is too large Load Diff