Compare commits
	
		
			42 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0afa80345d | |||
| 
						
						
							
						
						dbb0d177b8
	
				 | 
					
					
						|||
| 4ffc06db7b | |||
| 
						
						
							
						
						588f3bae89
	
				 | 
					
					
						|||
| d889432ce8 | |||
| 
						
						
							
						
						44830f08bc
	
				 | 
					
					
						|||
| 1cd3ebf8c5 | |||
| 
						
						
							
						
						558b69eeaa
	
				 | 
					
					
						|||
| 
						
						
							
						
						2b22063a81
	
				 | 
					
					
						|||
| 
						
						
							
						
						48cc380504
	
				 | 
					
					
						|||
| 
						
						
							
						
						75473cabe7
	
				 | 
					
					
						|||
| 
						
						
							
						
						6420ffb055
	
				 | 
					
					
						|||
| a62ee63c83 | |||
| 
						
						
							
						
						c89f2a2939
	
				 | 
					
					
						|||
| 
						
						
							
						
						d51c58867d
	
				 | 
					
					
						|||
| 
						
						
							
						
						2fa520fdde
	
				 | 
					
					
						|||
| 
						
						
							
						
						5bb7212420
	
				 | 
					
					
						|||
| 
						
						
							
						
						2226705e3f
	
				 | 
					
					
						|||
| 72932955d1 | |||
| 
						
						
							
						
						339e2f39d8
	
				 | 
					
					
						|||
| 
						
						
							
						
						12c6d7e3da
	
				 | 
					
					
						|||
| 
						
						
							
						
						1624e666e8
	
				 | 
					
					
						|||
| 86f4cd00ea | |||
| 
						
						
							
						
						518aa3eb08
	
				 | 
					
					
						|||
| 86985ef735 | |||
| 
						
						
							
						
						fef7daaf96
	
				 | 
					
					
						|||
| b14fa05adc | |||
| 
						
						
							
						
						7c71e94304
	
				 | 
					
					
						|||
| 
						
						
							
						
						8fa489f2bc
	
				 | 
					
					
						|||
| 
						
						
							
						
						512acc0b8c
	
				 | 
					
					
						|||
| 567ac07612 | |||
| 
						
						
							
						
						fa01864d0d
	
				 | 
					
					
						|||
| 
						
						
							
						
						91b25c22ca
	
				 | 
					
					
						|||
| 
						
						
							
						
						55d6b91cc2
	
				 | 
					
					
						|||
| 
						
						
							
						
						807eb9c267
	
				 | 
					
					
						|||
| e02d91e662 | |||
| 
						
						
							
						
						8d9cf8d1b3
	
				 | 
					
					
						|||
| 
						
						
							
						
						d97450cf53
	
				 | 
					
					
						|||
| 
						
						
							
						
						fd0a586ed6
	
				 | 
					
					
						|||
| 
						
						
							
						
						af6500ccb4
	
				 | 
					
					
						|||
| 
						
						
							
						
						9a3c55d235
	
				 | 
					
					
						|||
| 
						
						
							
						
						86ef277c90
	
				 | 
					
					
						
							
								
								
									
										3
									
								
								.env
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								.env
									
									
									
									
									
								
							@@ -1,3 +1,4 @@
 | 
				
			|||||||
SSL=false
 | 
					SSL=true
 | 
				
			||||||
 | 
					DOMAIN=kauft.es
 | 
				
			||||||
DISABLE_PROVIDERS=false
 | 
					DISABLE_PROVIDERS=false
 | 
				
			||||||
ENABLE_REGISTER=true
 | 
					ENABLE_REGISTER=true
 | 
				
			||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -58,7 +58,6 @@ jspm_packages/
 | 
				
			|||||||
.yarn/build-state.yml
 | 
					.yarn/build-state.yml
 | 
				
			||||||
.yarn/install-state.gz
 | 
					.yarn/install-state.gz
 | 
				
			||||||
.pnp.*
 | 
					.pnp.*
 | 
				
			||||||
yarn.lock
 | 
					 | 
				
			||||||
package-lock.json
 | 
					package-lock.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*.sqlite*
 | 
					*.sqlite*
 | 
				
			||||||
							
								
								
									
										94
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										94
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -2,11 +2,105 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
 | 
					All notable changes to this project will be documented in this file. Dates are displayed in UTC.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.4.3](https://git.odit.services/kauft.es/linkylinky/compare/0.4.2...0.4.3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixed auth error crashing the entire server thanks to fastify handling stuff not the same way that they do in the docs..... [`#1`](https://git.odit.services/kauft.es/linkylinky/issues/1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.4.2](https://git.odit.services/kauft.es/linkylinky/compare/0.4.1...0.4.2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 18 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Changed register api route and added user deletion route [`588f3ba`](https://git.odit.services/kauft.es/linkylinky/commit/588f3bae8980f76461d20e15475ec797078b0b54)
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.4.2 [`4ffc06d`](https://git.odit.services/kauft.es/linkylinky/commit/4ffc06db7bb84bc7bfc9c57a80927f7201185274)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.4.1](https://git.odit.services/kauft.es/linkylinky/compare/0.4.0...0.4.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 18 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.4.1 [`d889432`](https://git.odit.services/kauft.es/linkylinky/commit/d889432ce8a403f6a609423eaf458a5904dc5b98)
 | 
				
			||||||
 | 
					- Fixed jwtcount not being recognized [`44830f0`](https://git.odit.services/kauft.es/linkylinky/commit/44830f08bc212f8079b5ac2da3d51eedbe6d5c41)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.4.0](https://git.odit.services/kauft.es/linkylinky/compare/0.3.0...0.4.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 18 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Basic jwt implementation :party: [`75473ca`](https://git.odit.services/kauft.es/linkylinky/commit/75473cabe79975296e473002e16d3abafbd2635e)
 | 
				
			||||||
 | 
					- Implemented jwtcount basics [`48cc380`](https://git.odit.services/kauft.es/linkylinky/commit/48cc380504206ea08b3a5082f19ad10bdd7cf773)
 | 
				
			||||||
 | 
					- Implemented jwt count validation and update on logout [`558b69e`](https://git.odit.services/kauft.es/linkylinky/commit/558b69eeaa78ea015473c674d5f919d64128a930)
 | 
				
			||||||
 | 
					- Switched to fastify-auth to support multiple auth providers [`6420ffb`](https://git.odit.services/kauft.es/linkylinky/commit/6420ffb055f08348c54cd08a193aba5fe5ebc13a)
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.4.0 [`1cd3ebf`](https://git.odit.services/kauft.es/linkylinky/commit/1cd3ebf8c5a9413b93ab49c8813dad5c5c547cb2)
 | 
				
			||||||
 | 
					- All authenticated entpoints now accept jwtauth [`2b22063`](https://git.odit.services/kauft.es/linkylinky/commit/2b22063a81193c3d698525a050ef300e542c1f05)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.3.0](https://git.odit.services/kauft.es/linkylinky/compare/0.2.0...0.3.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 18 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Added license [`5bb7212`](https://git.odit.services/kauft.es/linkylinky/commit/5bb7212420ba102e743d62a47074191cdb264d2a)
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.3.0 [`a62ee63`](https://git.odit.services/kauft.es/linkylinky/commit/a62ee63c838a64d7fd28ae110cad474e2c531995)
 | 
				
			||||||
 | 
					- Added stats api route [`c89f2a2`](https://git.odit.services/kauft.es/linkylinky/commit/c89f2a2939b658ffc688646ccce32fc0e1530583)
 | 
				
			||||||
 | 
					- Added author info [`2fa520f`](https://git.odit.services/kauft.es/linkylinky/commit/2fa520fdde1d55b2766b4b03e394e21a4f6cbae5)
 | 
				
			||||||
 | 
					- Updated readme [`2226705`](https://git.odit.services/kauft.es/linkylinky/commit/2226705e3f57d7d2f3ef5a79947c3ab44ec62c38)
 | 
				
			||||||
 | 
					- Added comments [`d51c588`](https://git.odit.services/kauft.es/linkylinky/commit/d51c58867d7508c84f26c236e38567bc6a4adbed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.2.0](https://git.odit.services/kauft.es/linkylinky/compare/0.1.4...0.2.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 14 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.2.0 [`7293295`](https://git.odit.services/kauft.es/linkylinky/commit/72932955d15976947dd553c5deba51cbf541b215)
 | 
				
			||||||
 | 
					- Added ebay provider recognition [`12c6d7e`](https://git.odit.services/kauft.es/linkylinky/commit/12c6d7e3da5cb4de6a597b4639f313b8e4319646)
 | 
				
			||||||
 | 
					- Ebay provider resolution [`339e2f3`](https://git.odit.services/kauft.es/linkylinky/commit/339e2f39d88d42a961e1e495f319dc0663cdc0a6)
 | 
				
			||||||
 | 
					- Now recognizing with and without protocol [`1624e66`](https://git.odit.services/kauft.es/linkylinky/commit/1624e666e83e0afe346bcacb105ea1a1535f0690)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.1.4](https://git.odit.services/kauft.es/linkylinky/compare/0.1.3...0.1.4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 14 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Added cors [`518aa3e`](https://git.odit.services/kauft.es/linkylinky/commit/518aa3eb08cb72854812130d45b3b89afb074693)
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.1.4 [`86f4cd0`](https://git.odit.services/kauft.es/linkylinky/commit/86f4cd00ea517f7e2cacbf69f2163eae597610ee)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.1.3](https://git.odit.services/kauft.es/linkylinky/compare/0.1.2...0.1.3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 14 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Weired knex env fix [`fef7daa`](https://git.odit.services/kauft.es/linkylinky/commit/fef7daaf961e9112aa00f2ad22c3b0518ad258a7)
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.1.3 [`86985ef`](https://git.odit.services/kauft.es/linkylinky/commit/86985ef7355c2db09dcd6c8e52ee7ebde3ed4128)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.1.2](https://git.odit.services/kauft.es/linkylinky/compare/0.1.1...0.1.2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 14 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- API Endpoint to get all short urls [`fa01864`](https://git.odit.services/kauft.es/linkylinky/commit/fa01864d0de7921e741d63c3f5795161279ea478)
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.1.2 [`b14fa05`](https://git.odit.services/kauft.es/linkylinky/commit/b14fa05adc1ef8e34fd73bf5f495505df7d44b33)
 | 
				
			||||||
 | 
					- Changed the way that the migration get's triggered [`8fa489f`](https://git.odit.services/kauft.es/linkylinky/commit/8fa489f2bcd9d1ad63ab4581b7f3b27eee3d9038)
 | 
				
			||||||
 | 
					- Get all api endpoints [`91b25c2`](https://git.odit.services/kauft.es/linkylinky/commit/91b25c22ca035aec5cc2fdc80ca4fbb56a2f8b65)
 | 
				
			||||||
 | 
					- Added optional db volume to docker-compose [`7c71e94`](https://git.odit.services/kauft.es/linkylinky/commit/7c71e943041d8e3ac9dcf95cad27f2f0bc0b024c)
 | 
				
			||||||
 | 
					- Prod db now resides in db folder [`512acc0`](https://git.odit.services/kauft.es/linkylinky/commit/512acc0b8c15d4cfbafef21ec20707bac4629ea4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.1.1](https://git.odit.services/kauft.es/linkylinky/compare/0.1.0...0.1.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 14 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.1.1 [`55d6b91`](https://git.odit.services/kauft.es/linkylinky/commit/55d6b91cc252ee6676d13df9abd8b61283a07f0f)
 | 
				
			||||||
 | 
					- fix: Dockerfile [`807eb9c`](https://git.odit.services/kauft.es/linkylinky/commit/807eb9c267377df0b5f30f81eb380ef8a1c2add2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### [0.1.0](https://git.odit.services/kauft.es/linkylinky/compare/0.0.2...0.1.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 14 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- add lockfile [skip-ci] [`d97450c`](https://git.odit.services/kauft.es/linkylinky/commit/d97450cf5389965d8183b5719aad7e9e6f0181ae)
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.1.0 [`e02d91e`](https://git.odit.services/kauft.es/linkylinky/commit/e02d91e662e090b79b03ec77896100923464aa6b)
 | 
				
			||||||
 | 
					- smaller Dockerfile [skip-ci] [`86ef277`](https://git.odit.services/kauft.es/linkylinky/commit/86ef277c902aabb52acb5f846cb55406dc4d1095)
 | 
				
			||||||
 | 
					- Added tag commit args [`fd0a586`](https://git.odit.services/kauft.es/linkylinky/commit/fd0a586ed6e365801979c16d809a8254f64049be)
 | 
				
			||||||
 | 
					- Now signing release commits [`af6500c`](https://git.odit.services/kauft.es/linkylinky/commit/af6500ccb4792616f28bec77eda5c5e116422604)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 0.0.2
 | 
					#### 0.0.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 14 August 2021
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Migrated to knex [`823b211`](https://git.odit.services/kauft.es/linkylinky/commit/823b211c8c4fd4de3a6043696ca070101173aa1b)
 | 
					- Migrated to knex [`823b211`](https://git.odit.services/kauft.es/linkylinky/commit/823b211c8c4fd4de3a6043696ca070101173aa1b)
 | 
				
			||||||
- Added basics for auth [`6d417fa`](https://git.odit.services/kauft.es/linkylinky/commit/6d417fac1b4d77ab5552b75483cfc787d466e699)
 | 
					- Added basics for auth [`6d417fa`](https://git.odit.services/kauft.es/linkylinky/commit/6d417fac1b4d77ab5552b75483cfc787d466e699)
 | 
				
			||||||
- Initial [`ab17f91`](https://git.odit.services/kauft.es/linkylinky/commit/ab17f9148af6811a53bf323172d045cc71ecfb6d)
 | 
					- Initial [`ab17f91`](https://git.odit.services/kauft.es/linkylinky/commit/ab17f9148af6811a53bf323172d045cc71ecfb6d)
 | 
				
			||||||
 | 
					- 🚀RELEASE 0.0.2 [`a4bdb4d`](https://git.odit.services/kauft.es/linkylinky/commit/a4bdb4dca4aaba397688d43f1ec3a26cb2143dea)
 | 
				
			||||||
- Added image builds by drone [`1a8410c`](https://git.odit.services/kauft.es/linkylinky/commit/1a8410c421e30001ae9623c19a8e72e0632ed920)
 | 
					- Added image builds by drone [`1a8410c`](https://git.odit.services/kauft.es/linkylinky/commit/1a8410c421e30001ae9623c19a8e72e0632ed920)
 | 
				
			||||||
- Working registration/auth [`81b314a`](https://git.odit.services/kauft.es/linkylinky/commit/81b314ac55e9ab0cd603dda48473c0fe3db6c42e)
 | 
					- Working registration/auth [`81b314a`](https://git.odit.services/kauft.es/linkylinky/commit/81b314ac55e9ab0cd603dda48473c0fe3db6c42e)
 | 
				
			||||||
- Implemented short code generation via nanoid [`1550860`](https://git.odit.services/kauft.es/linkylinky/commit/15508606a41057857cce0d2ae16e389432c76960)
 | 
					- Implemented short code generation via nanoid [`1550860`](https://git.odit.services/kauft.es/linkylinky/commit/15508606a41057857cce0d2ae16e389432c76960)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -1,15 +1,17 @@
 | 
				
			|||||||
FROM node:16-alpine as run
 | 
					FROM node:16.6.2-alpine3.14
 | 
				
			||||||
 | 
					WORKDIR /app
 | 
				
			||||||
COPY package.json .
 | 
					COPY package.json .
 | 
				
			||||||
RUN yarn --prod
 | 
					COPY yarn.lock .
 | 
				
			||||||
 | 
					RUN yarn --production --frozen-lockfile
 | 
				
			||||||
 | 
					COPY migrations ./migrations
 | 
				
			||||||
 | 
					COPY src ./src
 | 
				
			||||||
 | 
					COPY knexfile.js ./
 | 
				
			||||||
 | 
					RUN mkdir db
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
 | 
					# FROM astefanutti/scratch-node:16.0.0
 | 
				
			||||||
 | 
					FROM node:16.6.2-alpine3.14
 | 
				
			||||||
 | 
					WORKDIR /app
 | 
				
			||||||
 | 
					COPY --from=0 /app /app
 | 
				
			||||||
ENV NODE_ENV production
 | 
					ENV NODE_ENV production
 | 
				
			||||||
EXPOSE 3000
 | 
					EXPOSE 3000
 | 
				
			||||||
 | 
					ENTRYPOINT ["/bin/sh", "-c", "yarn migrate && node ./src/server.js"]
 | 
				
			||||||
WORKDIR /app
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
COPY migrations ./migrations
 | 
					 | 
				
			||||||
COPY src/server.js ./
 | 
					 | 
				
			||||||
COPY knexfile.js ./
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CMD ["node", "./server.js"]
 | 
					 | 
				
			||||||
							
								
								
									
										24
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					MIT License
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2021 ODIT.Services (https://odit.services)
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person
 | 
				
			||||||
 | 
					obtaining a copy of this software and associated documentation
 | 
				
			||||||
 | 
					files (the "Software"), to deal in the Software without
 | 
				
			||||||
 | 
					restriction, including without limitation the rights to use,
 | 
				
			||||||
 | 
					copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the
 | 
				
			||||||
 | 
					Software is furnished to do so, subject to the following
 | 
				
			||||||
 | 
					conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be
 | 
				
			||||||
 | 
					included in all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
				
			||||||
 | 
					EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 | 
				
			||||||
 | 
					OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
				
			||||||
 | 
					NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 | 
				
			||||||
 | 
					HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 | 
				
			||||||
 | 
					WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
				
			||||||
 | 
					FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
				
			||||||
 | 
					OTHER DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
# LinkyLinky 🔗
 | 
					<p align="center">
 | 
				
			||||||
> A small url shortener, originaly developed for kauft.es
 | 
					  <img height="150" src="https://git.odit.services/user/avatar/kauft.es/140">
 | 
				
			||||||
 | 
					  <h1 align="center">LinkyLinky 🔗</h1>
 | 
				
			||||||
 | 
					  <h3 align="center">A small url shortener, originaly developed for kauft.es</h3>
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Dev Setup 🛠
 | 
					## Dev Setup 🛠
 | 
				
			||||||
> Runs on port 3000
 | 
					> Runs on port 3000
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,3 +5,5 @@ services:
 | 
				
			|||||||
    #image: registry.odit.services/kauft.es/linkylinky:latest
 | 
					    #image: registry.odit.services/kauft.es/linkylinky:latest
 | 
				
			||||||
    ports:
 | 
					    ports:
 | 
				
			||||||
      - 3000:3000
 | 
					      - 3000:3000
 | 
				
			||||||
 | 
					    #volumes:
 | 
				
			||||||
 | 
					    #  - ./db:/app/db
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ module.exports = {
 | 
				
			|||||||
  production: {
 | 
					  production: {
 | 
				
			||||||
    client: 'sqlite3',
 | 
					    client: 'sqlite3',
 | 
				
			||||||
    connection: {
 | 
					    connection: {
 | 
				
			||||||
      filename: './db.sqlite3'
 | 
					      filename: './db/db.sqlite3'
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    migrations: {
 | 
					    migrations: {
 | 
				
			||||||
      tableName: 'knex_migrations'
 | 
					      tableName: 'knex_migrations'
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								migrations/20210818160424_jwtcount.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								migrations/20210818160424_jwtcount.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					exports.up = function(knex) {
 | 
				
			||||||
 | 
					    return knex.schema.table('users', function (table) {
 | 
				
			||||||
 | 
					        table.integer("jwtcount").defaultTo(0);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exports.down = function(knex) {
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										23
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								package.json
									
									
									
									
									
								
							@@ -1,9 +1,21 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@odit/shortener-backend",
 | 
					  "name": "@odit/shortener-backend",
 | 
				
			||||||
  "version": "0.0.2",
 | 
					  "version": "0.4.3",
 | 
				
			||||||
  "main": "index.js",
 | 
					  "main": "index.js",
 | 
				
			||||||
  "license": "MIT",
 | 
					  "license": "MIT",
 | 
				
			||||||
  "private": false,
 | 
					  "private": false,
 | 
				
			||||||
 | 
					  "author": {
 | 
				
			||||||
 | 
					    "name": "ODIT.Services",
 | 
				
			||||||
 | 
					    "email": "info@odit.services",
 | 
				
			||||||
 | 
					    "url": "https://odit.services"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "contributors": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "name": "Nicolai Ort",
 | 
				
			||||||
 | 
					      "email": "info@nicolai-ort.com",
 | 
				
			||||||
 | 
					      "url": "https://nicolai-ort.com"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "dev": "nodemon src/server.js",
 | 
					    "dev": "nodemon src/server.js",
 | 
				
			||||||
    "start": "node src/server.js",
 | 
					    "start": "node src/server.js",
 | 
				
			||||||
@@ -14,7 +26,10 @@
 | 
				
			|||||||
    "argon2": "^0.28.2",
 | 
					    "argon2": "^0.28.2",
 | 
				
			||||||
    "dotenv": "^10.0.0",
 | 
					    "dotenv": "^10.0.0",
 | 
				
			||||||
    "fastify": "^3.20.1",
 | 
					    "fastify": "^3.20.1",
 | 
				
			||||||
 | 
					    "fastify-auth": "^1.1.0",
 | 
				
			||||||
    "fastify-basic-auth": "^2.1.0",
 | 
					    "fastify-basic-auth": "^2.1.0",
 | 
				
			||||||
 | 
					    "fastify-cors": "^6.0.2",
 | 
				
			||||||
 | 
					    "fastify-jwt": "^3.0.1",
 | 
				
			||||||
    "knex": "^0.21.21",
 | 
					    "knex": "^0.21.21",
 | 
				
			||||||
    "sqlite3": "^5.0.2",
 | 
					    "sqlite3": "^5.0.2",
 | 
				
			||||||
    "uniqid": "^5.3.0"
 | 
					    "uniqid": "^5.3.0"
 | 
				
			||||||
@@ -28,6 +43,12 @@
 | 
				
			|||||||
      "commit": true,
 | 
					      "commit": true,
 | 
				
			||||||
      "requireCleanWorkingDir": false,
 | 
					      "requireCleanWorkingDir": false,
 | 
				
			||||||
      "commitMessage": "🚀RELEASE ${version}",
 | 
					      "commitMessage": "🚀RELEASE ${version}",
 | 
				
			||||||
 | 
					      "git.commitArgs": [
 | 
				
			||||||
 | 
					        "-S"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "git.tagArgs": [
 | 
				
			||||||
 | 
					        "-S"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
      "push": true,
 | 
					      "push": true,
 | 
				
			||||||
      "tag": true,
 | 
					      "tag": true,
 | 
				
			||||||
      "tagName": null,
 | 
					      "tagName": null,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										163
									
								
								src/server.js
									
									
									
									
									
								
							
							
						
						
									
										163
									
								
								src/server.js
									
									
									
									
									
								
							@@ -6,8 +6,10 @@ const argon2 = require('argon2');
 | 
				
			|||||||
let config = {
 | 
					let config = {
 | 
				
			||||||
    domain: process.env.DOMAIN || "localhost:3000",
 | 
					    domain: process.env.DOMAIN || "localhost:3000",
 | 
				
			||||||
    https: (process.env.SSL === 'true') || false,
 | 
					    https: (process.env.SSL === 'true') || false,
 | 
				
			||||||
 | 
					    env: process.env.NODE_ENV || 'development',
 | 
				
			||||||
    recognizeProviders: !(process.env.DISABLE_PROVIDERS === 'true'),
 | 
					    recognizeProviders: !(process.env.DISABLE_PROVIDERS === 'true'),
 | 
				
			||||||
    registrationEnabled: (process.env.ENABLE_REGISTER === 'true'),
 | 
					    registrationEnabled: (process.env.ENABLE_REGISTER === 'true'),
 | 
				
			||||||
 | 
					    jwt_secret: process.env.JWT_SECRET || "pleaseneverusethisdefaultsecret",
 | 
				
			||||||
    getBaseUrl() {
 | 
					    getBaseUrl() {
 | 
				
			||||||
        if (config.https) {
 | 
					        if (config.https) {
 | 
				
			||||||
            return `https://${config.domain}`;
 | 
					            return `https://${config.domain}`;
 | 
				
			||||||
@@ -15,16 +17,60 @@ let config = {
 | 
				
			|||||||
        return `http://${config.domain}`;
 | 
					        return `http://${config.domain}`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					const knexConfiguration = require('../knexfile')[config.env];
 | 
				
			||||||
const knex = require('knex')({
 | 
					const knex = require('knex')(knexConfiguration);
 | 
				
			||||||
    client: 'sqlite3',
 | 
					 | 
				
			||||||
    connection: {
 | 
					 | 
				
			||||||
        filename: "./dev.sqlite3"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const authenticate = { realm: 'Short' }
 | 
					const authenticate = { realm: 'Short' }
 | 
				
			||||||
 | 
					fastify.register(require('fastify-auth'))
 | 
				
			||||||
fastify.register(require('fastify-basic-auth'), { validate, authenticate });
 | 
					fastify.register(require('fastify-basic-auth'), { validate, authenticate });
 | 
				
			||||||
 | 
					fastify.register(require('fastify-jwt'), {
 | 
				
			||||||
 | 
					    secret: config.jwt_secret
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					fastify.register(require('fastify-cors'), {
 | 
				
			||||||
 | 
					    origin: true,
 | 
				
			||||||
 | 
					    preflight: true,
 | 
				
			||||||
 | 
					    preflightContinue: true
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fastify.decorate('verifyJWT', function async(request, reply, done) {
 | 
				
			||||||
 | 
					    let token = request.headers.authorization;
 | 
				
			||||||
 | 
					    if (!token || token == "" || token == "Bearer") {
 | 
				
			||||||
 | 
					        done(new Error("No jwt provided"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (token.startsWith("Bearer")) {
 | 
				
			||||||
 | 
					        token = token.replace("Bearer ", "");
 | 
				
			||||||
 | 
					        fastify.log.info("Detected bearer and replaced it")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fastify.jwt.verify(token, async (err, decoded) => {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            fastify.log.error("JWT validation failed:")
 | 
				
			||||||
 | 
					            done(new Error("JWT Validation failed"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            if (!decoded.payload) {
 | 
				
			||||||
 | 
					                done(new Error("JWT is empty"));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            fastify.log.info(`Token verified. User is ${decoded.payload.user}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const jwtcount = (await knex.select('jwtcount')
 | 
				
			||||||
 | 
					                .from('users')
 | 
				
			||||||
 | 
					                .where('username', '=', decoded.payload.user)
 | 
				
			||||||
 | 
					                .limit(1))[0].jwtcount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (decoded.payload.jwtcount < jwtcount) {
 | 
				
			||||||
 | 
					                fastify.log.error("Auth ended at jwtcount")
 | 
				
			||||||
 | 
					                done(new Error("JWT in no longer valid"))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                fastify.log.info(`JWT count verified`);
 | 
				
			||||||
 | 
					                request.user = decoded.payload.user;
 | 
				
			||||||
 | 
					                done()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Automagic Amazn redirects on /a/
 | 
					//Automagic Amazn redirects on /a/
 | 
				
			||||||
fastify.get('/a/:id', async (req, res) => {
 | 
					fastify.get('/a/:id', async (req, res) => {
 | 
				
			||||||
@@ -40,6 +86,11 @@ fastify.get('/ytpl/:id', async (req, res) => {
 | 
				
			|||||||
    res.redirect(302, `https://youtube.com/playlist?list=${req.params.id}`)
 | 
					    res.redirect(302, `https://youtube.com/playlist?list=${req.params.id}`)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Automagic ebay item redirects on /e/
 | 
				
			||||||
 | 
					fastify.get('/e/:id', async (req, res) => {
 | 
				
			||||||
 | 
					    res.redirect(302, `https://ebay.de/itm/${req.params.id}`)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Normal shorturls
 | 
					//Normal shorturls
 | 
				
			||||||
fastify.get('/:shortcode', async (req, res) => {
 | 
					fastify.get('/:shortcode', async (req, res) => {
 | 
				
			||||||
    const shortcode = req.params.shortcode;
 | 
					    const shortcode = req.params.shortcode;
 | 
				
			||||||
@@ -133,6 +184,20 @@ fastify.post('/api', { newUrlSchema }, async (req, res) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Get stats api route
 | 
				
			||||||
 | 
					fastify.get('/api/stats', async (req, res) => {
 | 
				
			||||||
 | 
					    const urls = await knex.select('shortcode')
 | 
				
			||||||
 | 
					        .from('urls');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const visits = await knex.select('timestamp')
 | 
				
			||||||
 | 
					        .from('visits');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        urls: urls.length,
 | 
				
			||||||
 | 
					        visits: visits.length,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Get url api route
 | 
					//Get url api route
 | 
				
			||||||
fastify.get('/api/:shortcode', async (req, res) => {
 | 
					fastify.get('/api/:shortcode', async (req, res) => {
 | 
				
			||||||
    const shortcode = req.params.shortcode;
 | 
					    const shortcode = req.params.shortcode;
 | 
				
			||||||
@@ -162,8 +227,9 @@ fastify.get('/api/:shortcode', async (req, res) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//User registration
 | 
					//User registration
 | 
				
			||||||
fastify.post('/api/register', async (req, res) => {
 | 
					fastify.post('/api/auth/register', async (req, res) => {
 | 
				
			||||||
    if (!config.registrationEnabled) {
 | 
					    if (!config.registrationEnabled) {
 | 
				
			||||||
        res.statusCode = 400;
 | 
					        res.statusCode = 400;
 | 
				
			||||||
        return "Registration was disabled by your admin";
 | 
					        return "Registration was disabled by your admin";
 | 
				
			||||||
@@ -195,9 +261,10 @@ fastify.post('/api/register', async (req, res) => {
 | 
				
			|||||||
    return "Done!"
 | 
					    return "Done!"
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Anything in here has some kind of auth
 | 
				
			||||||
fastify.after(() => {
 | 
					fastify.after(() => {
 | 
				
			||||||
    //Get url api route
 | 
					    //Get url api route
 | 
				
			||||||
    fastify.get('/api/:shortcode/visits', { onRequest: fastify.basicAuth }, async (req, res) => {
 | 
					    fastify.get('/api/:shortcode/visits', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, res) => {
 | 
				
			||||||
        const shortcode = req.params.shortcode;
 | 
					        const shortcode = req.params.shortcode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //This should never happen but better safe than 500
 | 
					        //This should never happen but better safe than 500
 | 
				
			||||||
@@ -221,7 +288,7 @@ fastify.after(() => {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Get url api route
 | 
					    //Get url api route
 | 
				
			||||||
    fastify.delete('/api/:shortcode', async (req, res) => {
 | 
					    fastify.delete('/api/:shortcode', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, res) => {
 | 
				
			||||||
        const shortcode = req.params.shortcode;
 | 
					        const shortcode = req.params.shortcode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //This should never happen but better safe than 500
 | 
					        //This should never happen but better safe than 500
 | 
				
			||||||
@@ -237,6 +304,63 @@ fastify.after(() => {
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Get all urls api route
 | 
				
			||||||
 | 
					    fastify.get('/api', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, res) => {
 | 
				
			||||||
 | 
					        urls = await knex.select('target', 'shortcode')
 | 
				
			||||||
 | 
					            .from('urls');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let url of urls) {
 | 
				
			||||||
 | 
					            url.url = `${config.getBaseUrl()}/${url.shortcode}`
 | 
				
			||||||
 | 
					            if (req.query.showVisits) {
 | 
				
			||||||
 | 
					                url.visits = (await knex.select('timestamp')
 | 
				
			||||||
 | 
					                    .from('visits')
 | 
				
			||||||
 | 
					                    .where('shortcode', '=', url.shortcode)).length;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return urls;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fastify.post('/api/auth/login', { onRequest: fastify.auth([fastify.basicAuth]) }, async (req, reply) => {
 | 
				
			||||||
 | 
					        const jwtcount = (await knex.select('jwtcount')
 | 
				
			||||||
 | 
					            .from('users')
 | 
				
			||||||
 | 
					            .where('username', '=', req.user)
 | 
				
			||||||
 | 
					            .limit(1))[0].jwtcount;
 | 
				
			||||||
 | 
					        const payload = {
 | 
				
			||||||
 | 
					            user: req.user,
 | 
				
			||||||
 | 
					            jwtcount
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        const token = fastify.jwt.sign({ payload })
 | 
				
			||||||
 | 
					        reply.send({ token });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fastify.post('/api/auth/check', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, (req, reply) => {
 | 
				
			||||||
 | 
					        return "logged in";
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fastify.post('/api/auth/logout', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, reply) => {
 | 
				
			||||||
 | 
					        let jwtcount = (await knex.select('jwtcount')
 | 
				
			||||||
 | 
					            .from('users')
 | 
				
			||||||
 | 
					            .where('username', '=', req.user)
 | 
				
			||||||
 | 
					            .limit(1))[0].jwtcount;
 | 
				
			||||||
 | 
					        jwtcount += 1;
 | 
				
			||||||
 | 
					        await knex('users')
 | 
				
			||||||
 | 
					            .where('username', '=', req.user)
 | 
				
			||||||
 | 
					            .update({
 | 
				
			||||||
 | 
					                jwtcount
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return "Done!";
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fastify.post('/api/auth/deleteme', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, reply) => {
 | 
				
			||||||
 | 
					        await knex('users')
 | 
				
			||||||
 | 
					            .where('username', '=', req.user)
 | 
				
			||||||
 | 
					            .delete();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return "Done!";
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -266,7 +390,7 @@ function checkKnownProviders(target) {
 | 
				
			|||||||
            target
 | 
					            target
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const amazonID = target.match(/https?:\/\/(www|smile|)\.?(amazon|smile)\.(de)(?:(?:\/.*\/|\/)(?:dp|gp))(\/product\/|\/)([A-Z0-9]+)/);
 | 
					    const amazonID = target.match(/(?:https?:\/\/|)(www|smile|)\.?(amazon|smile)\.(de)(?:(?:\/.*\/|\/)(?:dp|gp))(\/product\/|\/)([A-Z0-9]+)/);
 | 
				
			||||||
    if (amazonID) {
 | 
					    if (amazonID) {
 | 
				
			||||||
        const shortcode = `a/${amazonID[5]}`
 | 
					        const shortcode = `a/${amazonID[5]}`
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
@@ -275,6 +399,15 @@ function checkKnownProviders(target) {
 | 
				
			|||||||
            target
 | 
					            target
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const ebayID = target.match(/(?:[ebay]*(?:[\/]|[itm=])|^)([0-9]{9,12})/);
 | 
				
			||||||
 | 
					    if (ebayID) {
 | 
				
			||||||
 | 
					        const shortcode = `e/${ebayID[1]}`
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            url: `${config.getBaseUrl()}/${shortcode}`,
 | 
				
			||||||
 | 
					            shortcode,
 | 
				
			||||||
 | 
					            target
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -294,17 +427,11 @@ async function validate(username, password, req, reply) {
 | 
				
			|||||||
    if (!(await argon2.verify(user[0].password, password))) {
 | 
					    if (!(await argon2.verify(user[0].password, password))) {
 | 
				
			||||||
        return new Error('Wrong credentials');
 | 
					        return new Error('Wrong credentials');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    req.user = username;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Run the server!
 | 
					// Run the server!
 | 
				
			||||||
const start = async () => {
 | 
					const start = async () => {
 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
        await knex.migrate.latest()
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					 | 
				
			||||||
        fastify.log.error(err)
 | 
					 | 
				
			||||||
        process.exit(1)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
        await fastify.listen(3000, '0.0.0.0')
 | 
					        await fastify.listen(3000, '0.0.0.0')
 | 
				
			||||||
    } catch (err) {
 | 
					    } catch (err) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user