Compare commits
	
		
			61 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 3803ac9197 | |||
| 
						
						
							
						
						e1621b72ad
	
				 | 
					
					
						|||
| 
						
						
							
						
						b64a8436e7
	
				 | 
					
					
						|||
| 
						
						
							
						
						d8ed9a149f
	
				 | 
					
					
						|||
| 
						
						
							
						
						9d7125a311
	
				 | 
					
					
						|||
| 
						
						
							
						
						6d71a3ebf4
	
				 | 
					
					
						|||
| 
						
						
							
						
						75adbf73cf
	
				 | 
					
					
						|||
| 
						
						
							
						
						e5b8557e4c
	
				 | 
					
					
						|||
| 
						
						
							
						
						33d7c94648
	
				 | 
					
					
						|||
| 
						
						
							
						
						f6b2ae523d
	
				 | 
					
					
						|||
| 
						
						
							
						
						0a500f16cd
	
				 | 
					
					
						|||
| 
						
						
							
						
						61da5d8110
	
				 | 
					
					
						|||
| 
						
						
							
						
						773b286216
	
				 | 
					
					
						|||
| 
						
						
							
						
						d097eccbd9
	
				 | 
					
					
						|||
| 
						
						
							
						
						f15282a3f9
	
				 | 
					
					
						|||
| 
						
						
							
						
						0a8945a294
	
				 | 
					
					
						|||
| b871e4295d | |||
| 
						
						
							
						
						0945060a49
	
				 | 
					
					
						|||
| 
						
						
							
						
						f7eae96b8c
	
				 | 
					
					
						|||
| 
						
						
							
						
						c2a50a1480
	
				 | 
					
					
						|||
| 
						
						
							
						
						bb99c2dcd1
	
				 | 
					
					
						|||
| e8382fb579 | |||
| 
						
						
							
						
						b5321377bd
	
				 | 
					
					
						|||
| 
						
						
							
						
						6e26bbbf5f
	
				 | 
					
					
						|||
| 
						
						
							
						
						59e178476e
	
				 | 
					
					
						|||
| 
						
						
							
						
						824c109a42
	
				 | 
					
					
						|||
| 
						
						
							
						
						f48159b31b
	
				 | 
					
					
						|||
| 
						
						
							
						
						6195001d4b
	
				 | 
					
					
						|||
| 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
	
				 | 
					
					
						
							
								
								
									
										3
									
								
								.env
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								.env
									
									
									
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
SSL=false
 | 
			
		||||
SSL=true
 | 
			
		||||
DOMAIN=kauft.es
 | 
			
		||||
DISABLE_PROVIDERS=false
 | 
			
		||||
ENABLE_REGISTER=true
 | 
			
		||||
							
								
								
									
										120
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -2,8 +2,128 @@
 | 
			
		||||
 | 
			
		||||
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
 | 
			
		||||
 | 
			
		||||
#### [0.6.0](https://git.odit.services/kauft.es/linkylinky/compare/0.5.1...0.6.0)
 | 
			
		||||
 | 
			
		||||
- Now with custom opengraph (tm) [`9d7125a`](https://git.odit.services/kauft.es/linkylinky/commit/9d7125a31186f3b7f33df4875db12c67cf91f536)
 | 
			
		||||
- Added rudementary page content [`e1621b7`](https://git.odit.services/kauft.es/linkylinky/commit/e1621b72ade1fce381f30bcf310a6dcf8d1c65ea)
 | 
			
		||||
- Added migration for disallowing bot previews [`0a500f1`](https://git.odit.services/kauft.es/linkylinky/commit/0a500f16cde0b0e38a115dd4e76185a2a45dda49)
 | 
			
		||||
- Added basic bot checking [`61da5d8`](https://git.odit.services/kauft.es/linkylinky/commit/61da5d81108a4b86f92e1c05ca99372c6b188347)
 | 
			
		||||
- Now with working bad bot detection [`75adbf7`](https://git.odit.services/kauft.es/linkylinky/commit/75adbf73cfbf4fadf2cd632ecb687eff95749f52)
 | 
			
		||||
- New urls can now be created with disabled preview [`33d7c94`](https://git.odit.services/kauft.es/linkylinky/commit/33d7c94648d062ece3fa437e71ce1ded70324cd8)
 | 
			
		||||
- Added bot check for native short urls [`f6b2ae5`](https://git.odit.services/kauft.es/linkylinky/commit/f6b2ae523da149b72f2be6d9171584cdc0be6e99)
 | 
			
		||||
- Added package for bot recognition [`773b286`](https://git.odit.services/kauft.es/linkylinky/commit/773b286216c9e530ccdf3fbfcfe95fa938097be5)
 | 
			
		||||
- Getters now return the no_preview status [`e5b8557`](https://git.odit.services/kauft.es/linkylinky/commit/e5b8557e4ccae90981e675c2adae81236aa9144e)
 | 
			
		||||
- Added noindex header to all shorturl routes [`0a8945a`](https://git.odit.services/kauft.es/linkylinky/commit/0a8945a294de2bc5bce9410f3ebf20b8f5abd0a5)
 | 
			
		||||
- Switched docker base images to odit mirror [`d8ed9a1`](https://git.odit.services/kauft.es/linkylinky/commit/d8ed9a149fddae8e8cc61b78cbc940a9d7ade8f2)
 | 
			
		||||
- Updated opengraph type [`b64a843`](https://git.odit.services/kauft.es/linkylinky/commit/b64a8436e745d176cc49ef72434dce0f8f1bcc12)
 | 
			
		||||
- Log user agents [`f15282a`](https://git.odit.services/kauft.es/linkylinky/commit/f15282a3f9bdaaf09a36d8662b64a5bc2740633f)
 | 
			
		||||
- Removed unused log [`6d71a3e`](https://git.odit.services/kauft.es/linkylinky/commit/6d71a3ebf4d880b8291cacd620f86416cff0d744)
 | 
			
		||||
- removed logging [`d097ecc`](https://git.odit.services/kauft.es/linkylinky/commit/d097eccbd925e3627fa710d7891d269b372d174c)
 | 
			
		||||
 | 
			
		||||
#### [0.5.1](https://git.odit.services/kauft.es/linkylinky/compare/0.5.0...0.5.1)
 | 
			
		||||
 | 
			
		||||
> 21 August 2021
 | 
			
		||||
 | 
			
		||||
- 🚀RELEASE 0.5.1 [`b871e42`](https://git.odit.services/kauft.es/linkylinky/commit/b871e4295dc4b067f4f4dd28c3f940c8aa9624e0)
 | 
			
		||||
- Added endpoint to query over all visited urls [`bb99c2d`](https://git.odit.services/kauft.es/linkylinky/commit/bb99c2dcd1ce89af1bc27a035be5265345d2a05f)
 | 
			
		||||
- Added optional filtering by provider [`0945060`](https://git.odit.services/kauft.es/linkylinky/commit/0945060a49ed35c038df2c04bbd07174bc5654ca)
 | 
			
		||||
- Shortened return to avoid variable memory asignment [`f7eae96`](https://git.odit.services/kauft.es/linkylinky/commit/f7eae96b8c3479d333fc00bc36bce451733700db)
 | 
			
		||||
- Changed object property order (just for us pesky humans to improve readability) [`c2a50a1`](https://git.odit.services/kauft.es/linkylinky/commit/c2a50a14807e223987464c63fac6d67ed98b1a93)
 | 
			
		||||
 | 
			
		||||
#### [0.5.0](https://git.odit.services/kauft.es/linkylinky/compare/0.4.3...0.5.0)
 | 
			
		||||
 | 
			
		||||
> 21 August 2021
 | 
			
		||||
 | 
			
		||||
- 🚀RELEASE 0.5.0 [`e8382fb`](https://git.odit.services/kauft.es/linkylinky/commit/e8382fb579f769364693974cbe74ce06e9810a9a)
 | 
			
		||||
- Removed visits 404 resolution [`59e1784`](https://git.odit.services/kauft.es/linkylinky/commit/59e178476e8f7e64de92ae23e859b87680e7af64)
 | 
			
		||||
- Added migration for visits provider [`f48159b`](https://git.odit.services/kauft.es/linkylinky/commit/f48159b31bcaf7c7449c89fb1e3851bcb04f5e3c)
 | 
			
		||||
- Reverted last change since we can defer it from the provider [`b532137`](https://git.odit.services/kauft.es/linkylinky/commit/b5321377bde9bd7de13e2eee4dd38a072cf0d4a3)
 | 
			
		||||
- Changed the way visits entrys get compiled to enable provider visits count searches over the default api [`6e26bbb`](https://git.odit.services/kauft.es/linkylinky/commit/6e26bbbf5f29e4c1eaa56c5dc41ab77c192d0cfb)
 | 
			
		||||
- Server now inserts provider on visit [`824c109`](https://git.odit.services/kauft.es/linkylinky/commit/824c109a420efd0e1e6de01d93827020f3fe5a5f)
 | 
			
		||||
- Added package script for migration creation [`6195001`](https://git.odit.services/kauft.es/linkylinky/commit/6195001d4b701d39470ff4be0e265f9afb288e78)
 | 
			
		||||
 | 
			
		||||
#### [0.4.3](https://git.odit.services/kauft.es/linkylinky/compare/0.4.2...0.4.3)
 | 
			
		||||
 | 
			
		||||
> 21 August 2021
 | 
			
		||||
 | 
			
		||||
- 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)
 | 
			
		||||
- 🚀RELEASE 0.4.3 [`0afa803`](https://git.odit.services/kauft.es/linkylinky/commit/0afa80345d47e09e20d4365634f8532248b2044c)
 | 
			
		||||
 | 
			
		||||
#### [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)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,17 @@
 | 
			
		||||
FROM node:16.6.2-alpine3.14
 | 
			
		||||
FROM registry.odit.services/hub/library/node:16.6.2-alpine3.14
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
COPY package.json .
 | 
			
		||||
COPY yarn.lock .
 | 
			
		||||
RUN yarn --production --frozen-lockfile
 | 
			
		||||
COPY migrations ./migrations
 | 
			
		||||
COPY src/server.js ./
 | 
			
		||||
COPY src ./src
 | 
			
		||||
COPY knexfile.js ./
 | 
			
		||||
RUN mkdir db
 | 
			
		||||
# 
 | 
			
		||||
# FROM astefanutti/scratch-node:16.0.0
 | 
			
		||||
FROM node:16.6.2-alpine3.14
 | 
			
		||||
FROM registry.odit.services/hub/library/node:16.6.2-alpine3.14
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
COPY --from=0 /app /app
 | 
			
		||||
ENV NODE_ENV production
 | 
			
		||||
EXPOSE 3000
 | 
			
		||||
ENTRYPOINT ["node", "./server.js"]
 | 
			
		||||
ENTRYPOINT ["/bin/sh", "-c", "yarn migrate && node ./src/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 🔗
 | 
			
		||||
> A small url shortener, originaly developed for kauft.es
 | 
			
		||||
<p align="center">
 | 
			
		||||
  <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 🛠
 | 
			
		||||
> Runs on port 3000
 | 
			
		||||
 
 | 
			
		||||
@@ -5,3 +5,5 @@ services:
 | 
			
		||||
    #image: registry.odit.services/kauft.es/linkylinky:latest
 | 
			
		||||
    ports:
 | 
			
		||||
      - 3000:3000
 | 
			
		||||
    #volumes:
 | 
			
		||||
    #  - ./db:/app/db
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ module.exports = {
 | 
			
		||||
  production: {
 | 
			
		||||
    client: 'sqlite3',
 | 
			
		||||
    connection: {
 | 
			
		||||
      filename: './db.sqlite3'
 | 
			
		||||
      filename: './db/db.sqlite3'
 | 
			
		||||
    },
 | 
			
		||||
    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) {
 | 
			
		||||
  
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										10
									
								
								migrations/20210821094219_visits_providers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								migrations/20210821094219_visits_providers.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
 | 
			
		||||
exports.up = function(knex) {
 | 
			
		||||
    return knex.schema.table('visits', function (table) {
 | 
			
		||||
        table.text('provider').defaultTo("N/A");
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.down = function(knex) {
 | 
			
		||||
  
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										10
									
								
								migrations/20210925171533_bot_preview.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								migrations/20210925171533_bot_preview.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
 | 
			
		||||
exports.up = function(knex) {
 | 
			
		||||
    return knex.schema.table('urls', function (table) {
 | 
			
		||||
        table.boolean('no_preview').defaultTo(false);
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.down = function(knex) {
 | 
			
		||||
  
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										21
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								package.json
									
									
									
									
									
								
							@@ -1,20 +1,37 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@odit/shortener-backend",
 | 
			
		||||
  "version": "0.1.1",
 | 
			
		||||
  "version": "0.6.0",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "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": {
 | 
			
		||||
    "dev": "nodemon src/server.js",
 | 
			
		||||
    "start": "node src/server.js",
 | 
			
		||||
    "migrate": "knex migrate:latest",
 | 
			
		||||
    "release": "release-it"
 | 
			
		||||
    "release": "release-it",
 | 
			
		||||
    "create:migration": "knex migrate:make"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "argon2": "^0.28.2",
 | 
			
		||||
    "dotenv": "^10.0.0",
 | 
			
		||||
    "fastify": "^3.20.1",
 | 
			
		||||
    "fastify-auth": "^1.1.0",
 | 
			
		||||
    "fastify-basic-auth": "^2.1.0",
 | 
			
		||||
    "fastify-cors": "^6.0.2",
 | 
			
		||||
    "fastify-jwt": "^3.0.1",
 | 
			
		||||
    "isbot": "^3.3.3",
 | 
			
		||||
    "knex": "^0.21.21",
 | 
			
		||||
    "sqlite3": "^5.0.2",
 | 
			
		||||
    "uniqid": "^5.3.0"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										241
									
								
								src/server.js
									
									
									
									
									
								
							
							
						
						
									
										241
									
								
								src/server.js
									
									
									
									
									
								
							@@ -2,12 +2,15 @@ const fastify = require('fastify')({ logger: true })
 | 
			
		||||
var uniqid = require('uniqid');
 | 
			
		||||
require('dotenv').config();
 | 
			
		||||
const argon2 = require('argon2');
 | 
			
		||||
const isBot = require('isbot')
 | 
			
		||||
 | 
			
		||||
let config = {
 | 
			
		||||
    domain: process.env.DOMAIN || "localhost:3000",
 | 
			
		||||
    https: (process.env.SSL === 'true') || false,
 | 
			
		||||
    env: process.env.NODE_ENV || 'development',
 | 
			
		||||
    recognizeProviders: !(process.env.DISABLE_PROVIDERS === 'true'),
 | 
			
		||||
    registrationEnabled: (process.env.ENABLE_REGISTER === 'true'),
 | 
			
		||||
    jwt_secret: process.env.JWT_SECRET || "pleaseneverusethisdefaultsecret",
 | 
			
		||||
    getBaseUrl() {
 | 
			
		||||
        if (config.https) {
 | 
			
		||||
            return `https://${config.domain}`;
 | 
			
		||||
@@ -15,29 +18,82 @@ let config = {
 | 
			
		||||
        return `http://${config.domain}`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const knex = require('knex')({
 | 
			
		||||
    client: 'sqlite3',
 | 
			
		||||
    connection: {
 | 
			
		||||
        filename: "./dev.sqlite3"
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
const knexConfiguration = require('../knexfile')[config.env];
 | 
			
		||||
const knex = require('knex')(knexConfiguration);
 | 
			
		||||
 | 
			
		||||
const authenticate = { realm: 'Short' }
 | 
			
		||||
fastify.register(require('fastify-auth'))
 | 
			
		||||
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/
 | 
			
		||||
fastify.get('/a/:id', async (req, res) => {
 | 
			
		||||
    res.redirect(302, `https://amazon.de/dp/${req.params.id}`)
 | 
			
		||||
    await knex('visits').insert({ shortcode: req.params.id, provider: 'a' });
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
//Automagic Youtube redirects on /yt/
 | 
			
		||||
fastify.get('/yt/:id', async (req, res) => {
 | 
			
		||||
    res.redirect(302, `https://youtu.be/${req.params.id}`)
 | 
			
		||||
    await knex('visits').insert({ shortcode: req.params.id, provider: 'yt' });
 | 
			
		||||
})
 | 
			
		||||
//Automagic Youtube Playlist redirects on /ytpl/
 | 
			
		||||
fastify.get('/ytpl/:id', async (req, res) => {
 | 
			
		||||
    res.redirect(302, `https://youtube.com/playlist?list=${req.params.id}`)
 | 
			
		||||
    await knex('visits').insert({ shortcode: req.params.id, provider: 'ytpl' });
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
//Automagic ebay item redirects on /e/
 | 
			
		||||
fastify.get('/e/:id', async (req, res) => {
 | 
			
		||||
    res.redirect(302, `https://ebay.de/itm/${req.params.id}`)
 | 
			
		||||
    await knex('visits').insert({ shortcode: req.params.id, provider: 'e' });
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
//Normal shorturls
 | 
			
		||||
@@ -48,15 +104,46 @@ fastify.get('/:shortcode', async (req, res) => {
 | 
			
		||||
    if (!shortcode) {
 | 
			
		||||
        return 404;
 | 
			
		||||
    }
 | 
			
		||||
    const target = await knex.select('target')
 | 
			
		||||
    const target = await knex.select('target', 'no_preview')
 | 
			
		||||
        .from('urls')
 | 
			
		||||
        .where('shortcode', '=', shortcode)
 | 
			
		||||
        .limit(1);
 | 
			
		||||
    if (!target[0]) {
 | 
			
		||||
        return 404
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isBot(req.headers['user-agent']) && target[0].no_preview) {
 | 
			
		||||
        return `
 | 
			
		||||
        <!DOCTYPE html>
 | 
			
		||||
        <html lang="en">
 | 
			
		||||
        <head>
 | 
			
		||||
            <meta charset="UTF-8">
 | 
			
		||||
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
            <meta property="og:title" content="LinkyLinky">
 | 
			
		||||
            <meta property="og:site_name" content="LinkyLinky by Kauft.es">
 | 
			
		||||
            <meta property="og:url" content="https://kauft.es/">
 | 
			
		||||
            <meta property="og:description" content="LinkyLinky by Kauft.es is a custom url shortener. You're reading this, b/c someone doesn't want their shorturl to be indexed by bots/crawlers/spiders.">
 | 
			
		||||
            <meta property="og:type" content="article">
 | 
			
		||||
            <meta property="og:image" content="https://kauft.es/dashboard/icon_128.png">
 | 
			
		||||
 | 
			
		||||
            <title>LinkyLinky</title>
 | 
			
		||||
        </head>
 | 
			
		||||
        <body>
 | 
			
		||||
        <p align="center">
 | 
			
		||||
        <img height="150" src="https://kauft.es/dashboard/icon_128.png">
 | 
			
		||||
        <h1 align="center">LinkyLinky 🔗</h1>
 | 
			
		||||
        <h3 align="center">A small url shortener, originaly developed for kauft.es</h3>
 | 
			
		||||
        <p>LinkyLinky by Kauft.es is a custom url shortener.<br>
 | 
			
		||||
        You're reading this, b/c someone doesn't want their shorturl to be indexed by bots/crawlers/spiders.</p>
 | 
			
		||||
        </p>        
 | 
			
		||||
        </body>
 | 
			
		||||
        </html>
 | 
			
		||||
        `;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    res.redirect(302, target[0].target);
 | 
			
		||||
    await knex('visits').insert({ shortcode });
 | 
			
		||||
    await knex('visits').insert({ shortcode, provider: 'native' });
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
//Create new url schema
 | 
			
		||||
@@ -66,6 +153,7 @@ const newUrlSchema = {
 | 
			
		||||
        properties: {
 | 
			
		||||
            target: { type: 'string' },
 | 
			
		||||
            shortcode: { type: 'string' },
 | 
			
		||||
            no_preview: { type: 'boolean' },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -74,6 +162,7 @@ const newUrlSchema = {
 | 
			
		||||
fastify.post('/api', { newUrlSchema }, async (req, res) => {
 | 
			
		||||
    const target = req.body?.target;
 | 
			
		||||
    let shortcode = req.body?.shortcode;
 | 
			
		||||
    let no_preview = req.body?.no_preview || false;
 | 
			
		||||
 | 
			
		||||
    //Check if the user provided a target
 | 
			
		||||
    if (!target) {
 | 
			
		||||
@@ -93,7 +182,7 @@ fastify.post('/api', { newUrlSchema }, async (req, res) => {
 | 
			
		||||
                return response;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        const exists = await knex.select('shortcode')
 | 
			
		||||
        const exists = await knex.select('shortcode', 'no_preview')
 | 
			
		||||
            .from('urls')
 | 
			
		||||
            .where('target', '=', target)
 | 
			
		||||
            .limit(1);
 | 
			
		||||
@@ -102,7 +191,8 @@ fastify.post('/api', { newUrlSchema }, async (req, res) => {
 | 
			
		||||
            return {
 | 
			
		||||
                url: `${config.getBaseUrl()}/${shortcode}`,
 | 
			
		||||
                shortcode,
 | 
			
		||||
                target
 | 
			
		||||
                target,
 | 
			
		||||
                no_preview: exists[0].no_preview
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        shortcode = uniqid();
 | 
			
		||||
@@ -124,12 +214,27 @@ fastify.post('/api', { newUrlSchema }, async (req, res) => {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Create a new db entry
 | 
			
		||||
    await knex('urls').insert({ target, shortcode });
 | 
			
		||||
    await knex('urls').insert({ target, shortcode, no_preview });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        url: `${config.getBaseUrl()}/${shortcode}`,
 | 
			
		||||
        shortcode,
 | 
			
		||||
        target
 | 
			
		||||
        target,
 | 
			
		||||
        no_preview
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
//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,
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -142,7 +247,7 @@ fastify.get('/api/:shortcode', async (req, res) => {
 | 
			
		||||
        return 404;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const exists = await knex.select('shortcode', 'target')
 | 
			
		||||
    const exists = await knex.select('shortcode', 'target', 'no_preview')
 | 
			
		||||
        .from('urls')
 | 
			
		||||
        .where('shortcode', '=', shortcode)
 | 
			
		||||
        .limit(1);
 | 
			
		||||
@@ -158,12 +263,14 @@ fastify.get('/api/:shortcode', async (req, res) => {
 | 
			
		||||
        url: `${config.getBaseUrl()}/${exists[0].shortcode}`,
 | 
			
		||||
        shortcode: exists[0].shortcode,
 | 
			
		||||
        target: exists[0].target,
 | 
			
		||||
        no_preview: exists[0].no_preview,
 | 
			
		||||
        visits: visits.length
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//User registration
 | 
			
		||||
fastify.post('/api/register', async (req, res) => {
 | 
			
		||||
fastify.post('/api/auth/register', async (req, res) => {
 | 
			
		||||
    if (!config.registrationEnabled) {
 | 
			
		||||
        res.statusCode = 400;
 | 
			
		||||
        return "Registration was disabled by your admin";
 | 
			
		||||
@@ -195,9 +302,10 @@ fastify.post('/api/register', async (req, res) => {
 | 
			
		||||
    return "Done!"
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
//Anything in here has some kind of auth
 | 
			
		||||
fastify.after(() => {
 | 
			
		||||
    //Get url api route
 | 
			
		||||
    fastify.get('/api/:shortcode/visits', { onRequest: fastify.basicAuth }, async (req, res) => {
 | 
			
		||||
    //Get url visits api route
 | 
			
		||||
    fastify.get('/api/:shortcode/visits', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, res) => {
 | 
			
		||||
        const shortcode = req.params.shortcode;
 | 
			
		||||
 | 
			
		||||
        //This should never happen but better safe than 500
 | 
			
		||||
@@ -205,23 +313,26 @@ fastify.after(() => {
 | 
			
		||||
            return 404;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const exists = await knex.select('shortcode', 'target')
 | 
			
		||||
            .from('urls')
 | 
			
		||||
            .where('shortcode', '=', shortcode)
 | 
			
		||||
            .limit(1);
 | 
			
		||||
        if (exists.length == 0) {
 | 
			
		||||
            return 404;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const visits = await knex.select('timestamp')
 | 
			
		||||
        const visits = await knex.select('timestamp', 'provider')
 | 
			
		||||
            .from('visits')
 | 
			
		||||
            .where('shortcode', '=', shortcode);
 | 
			
		||||
 | 
			
		||||
        return visits;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //Get all visits api route
 | 
			
		||||
    fastify.get('/api/visits', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, res) => {
 | 
			
		||||
        if (req.query.provider) {
 | 
			
		||||
            return await knex.select('shortcode', 'provider', 'timestamp')
 | 
			
		||||
                .from('visits')
 | 
			
		||||
                .where("provider", "=", req.query.provider);
 | 
			
		||||
        }
 | 
			
		||||
        return await knex.select('shortcode', 'provider', 'timestamp')
 | 
			
		||||
            .from('visits');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //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;
 | 
			
		||||
 | 
			
		||||
        //This should never happen but better safe than 500
 | 
			
		||||
@@ -237,6 +348,63 @@ fastify.after(() => {
 | 
			
		||||
        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', 'no_preview')
 | 
			
		||||
            .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 +434,7 @@ function checkKnownProviders(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) {
 | 
			
		||||
        const shortcode = `a/${amazonID[5]}`
 | 
			
		||||
        return {
 | 
			
		||||
@@ -275,6 +443,15 @@ function checkKnownProviders(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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -294,17 +471,11 @@ async function validate(username, password, req, reply) {
 | 
			
		||||
    if (!(await argon2.verify(user[0].password, password))) {
 | 
			
		||||
        return new Error('Wrong credentials');
 | 
			
		||||
    }
 | 
			
		||||
    req.user = username;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Run the server!
 | 
			
		||||
const start = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
        await knex.migrate.latest()
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        fastify.log.error(err)
 | 
			
		||||
        process.exit(1)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        await fastify.listen(3000, '0.0.0.0')
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										171
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										171
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -216,6 +216,13 @@
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
 | 
			
		||||
  integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==
 | 
			
		||||
 | 
			
		||||
"@types/jsonwebtoken@^8.5.0":
 | 
			
		||||
  version "8.5.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.4.tgz#50ccaf0aa6f5d7b9956e70fe323b76e582991913"
 | 
			
		||||
  integrity sha512-4L8msWK31oXwdtC81RmRBAULd0ShnAHjBuKT9MRQpjP0piNrZdXyTRcKY9/UIfhGeKIT4PvF5amOOUbbT/9Wpg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@types/node" "*"
 | 
			
		||||
 | 
			
		||||
"@types/keyv@*":
 | 
			
		||||
  version "3.1.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.2.tgz#5d97bb65526c20b6e0845f6b0d2ade4f28604ee5"
 | 
			
		||||
@@ -567,6 +574,11 @@ braces@^3.0.1, braces@~3.0.2:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    fill-range "^7.0.1"
 | 
			
		||||
 | 
			
		||||
buffer-equal-constant-time@1.0.1:
 | 
			
		||||
  version "1.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
 | 
			
		||||
  integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=
 | 
			
		||||
 | 
			
		||||
buffer@^5.5.0:
 | 
			
		||||
  version "5.7.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
 | 
			
		||||
@@ -1052,6 +1064,13 @@ ecc-jsbn@~0.1.1:
 | 
			
		||||
    jsbn "~0.1.0"
 | 
			
		||||
    safer-buffer "^2.1.0"
 | 
			
		||||
 | 
			
		||||
ecdsa-sig-formatter@1.0.11:
 | 
			
		||||
  version "1.0.11"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
 | 
			
		||||
  integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    safe-buffer "^5.0.1"
 | 
			
		||||
 | 
			
		||||
emoji-regex@^7.0.1:
 | 
			
		||||
  version "7.0.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
 | 
			
		||||
@@ -1240,6 +1259,21 @@ fast-safe-stringify@^2.0.8:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz#dc2af48c46cf712b683e849b2bbd446b32de936f"
 | 
			
		||||
  integrity sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==
 | 
			
		||||
 | 
			
		||||
fastfall@^1.5.0:
 | 
			
		||||
  version "1.5.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastfall/-/fastfall-1.5.1.tgz#3fee03331a49d1d39b3cdf7a5e9cd66f475e7b94"
 | 
			
		||||
  integrity sha1-P+4DMxpJ0dObPN96XpzWb0dee5Q=
 | 
			
		||||
  dependencies:
 | 
			
		||||
    reusify "^1.0.0"
 | 
			
		||||
 | 
			
		||||
fastify-auth@^1.1.0:
 | 
			
		||||
  version "1.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastify-auth/-/fastify-auth-1.1.0.tgz#75076c9c0664addaff07078907db6432086be1d6"
 | 
			
		||||
  integrity sha512-8IajmAZB3QJ3wTP0q8Z3TG9DkxrIcAlS85TdPCBEfJi3mMKQd/sCYxtZ0dYv11v5hZaJ9z8XmNzhK3AH6/JpNw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    fastify-plugin "^3.0.0"
 | 
			
		||||
    reusify "^1.0.4"
 | 
			
		||||
 | 
			
		||||
fastify-basic-auth@^2.1.0:
 | 
			
		||||
  version "2.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastify-basic-auth/-/fastify-basic-auth-2.1.0.tgz#a368e4e900f402a2c26f4cab927484b9f2ac539c"
 | 
			
		||||
@@ -1249,11 +1283,30 @@ fastify-basic-auth@^2.1.0:
 | 
			
		||||
    fastify-plugin "^3.0.0"
 | 
			
		||||
    http-errors "^1.7.3"
 | 
			
		||||
 | 
			
		||||
fastify-cors@^6.0.2:
 | 
			
		||||
  version "6.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastify-cors/-/fastify-cors-6.0.2.tgz#4fd5102549659e9b34d252fd7ee607b63d021390"
 | 
			
		||||
  integrity sha512-sE0AOyzmj5hLLRRVgenjA6G2iOGX35/1S3QGYB9rr9TXelMZB3lFrXy4CzwYVOMiujJeMiLgO4J7eRm8sQSv8Q==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    fastify-plugin "^3.0.0"
 | 
			
		||||
    vary "^1.1.2"
 | 
			
		||||
 | 
			
		||||
fastify-error@^0.3.0:
 | 
			
		||||
  version "0.3.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.3.1.tgz#8eb993e15e3cf57f0357fc452af9290f1c1278d2"
 | 
			
		||||
  integrity sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ==
 | 
			
		||||
 | 
			
		||||
fastify-jwt@^3.0.1:
 | 
			
		||||
  version "3.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastify-jwt/-/fastify-jwt-3.0.1.tgz#aaec719c7f103eb9fb648fda22690e3cec7911d4"
 | 
			
		||||
  integrity sha512-p6/7QSa9rdO/m4zCcq1oge63qXkfPsrdfPwVkay9HAGD4rh0UuntB/MeWLy+1ZHNay5foATvFB3A9nG15S7RsA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@types/jsonwebtoken" "^8.5.0"
 | 
			
		||||
    fastify-plugin "^3.0.0"
 | 
			
		||||
    http-errors "^1.8.0"
 | 
			
		||||
    jsonwebtoken "^8.5.1"
 | 
			
		||||
    steed "^1.1.3"
 | 
			
		||||
 | 
			
		||||
fastify-plugin@^3.0.0:
 | 
			
		||||
  version "3.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.0.tgz#cf1b8c8098e3b5a7c8c30e6aeb06903370c054ca"
 | 
			
		||||
@@ -1286,13 +1339,29 @@ fastify@^3.20.1:
 | 
			
		||||
    semver "^7.3.2"
 | 
			
		||||
    tiny-lru "^7.0.0"
 | 
			
		||||
 | 
			
		||||
fastq@^1.6.0, fastq@^1.6.1:
 | 
			
		||||
fastparallel@^2.2.0:
 | 
			
		||||
  version "2.4.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastparallel/-/fastparallel-2.4.0.tgz#65fbec1a5e5902494be772cf5765cbaaece08688"
 | 
			
		||||
  integrity sha512-sacwQ7wwKlQXsa7TN24UvMBLZNLmVcPhmxccC9riFqb3N+fSczJL8eWdnZodZ/KijGVgNBBfvF/NeXER08uXnQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    reusify "^1.0.4"
 | 
			
		||||
    xtend "^4.0.2"
 | 
			
		||||
 | 
			
		||||
fastq@^1.3.0, fastq@^1.6.0, fastq@^1.6.1:
 | 
			
		||||
  version "1.11.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.1.tgz#5d8175aae17db61947f8b162cfc7f63264d22807"
 | 
			
		||||
  integrity sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    reusify "^1.0.4"
 | 
			
		||||
 | 
			
		||||
fastseries@^1.7.0:
 | 
			
		||||
  version "1.7.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fastseries/-/fastseries-1.7.2.tgz#d22ce13b9433dff3388d91dbd6b8bda9b21a0f4b"
 | 
			
		||||
  integrity sha1-0izhO5Qz3/M4jZHb1ri9qbIaD0s=
 | 
			
		||||
  dependencies:
 | 
			
		||||
    reusify "^1.0.0"
 | 
			
		||||
    xtend "^4.0.0"
 | 
			
		||||
 | 
			
		||||
figures@^3.0.0:
 | 
			
		||||
  version "3.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
 | 
			
		||||
@@ -1728,7 +1797,7 @@ http-cache-semantics@^4.0.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
 | 
			
		||||
  integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
 | 
			
		||||
 | 
			
		||||
http-errors@^1.7.3:
 | 
			
		||||
http-errors@^1.7.3, http-errors@^1.8.0:
 | 
			
		||||
  version "1.8.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507"
 | 
			
		||||
  integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==
 | 
			
		||||
@@ -2159,6 +2228,11 @@ isarray@1.0.0, isarray@~1.0.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
 | 
			
		||||
  integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
 | 
			
		||||
 | 
			
		||||
isbot@^3.3.3:
 | 
			
		||||
  version "3.3.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/isbot/-/isbot-3.3.3.tgz#6a2124a6c1dda5db2d0060c4e292b346ecbd2249"
 | 
			
		||||
  integrity sha512-a3HFPPsvtLroqpuTHHJTaUpPHUO0vjPbptJDzJYkymRvOI8tugWM6zE2oq22w5VOq4A5hrX+YRS7VdIPAgWLfw==
 | 
			
		||||
 | 
			
		||||
isexe@^2.0.0:
 | 
			
		||||
  version "2.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
 | 
			
		||||
@@ -2221,6 +2295,22 @@ json-stringify-safe@~5.0.1:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
 | 
			
		||||
  integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
 | 
			
		||||
 | 
			
		||||
jsonwebtoken@^8.5.1:
 | 
			
		||||
  version "8.5.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
 | 
			
		||||
  integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    jws "^3.2.2"
 | 
			
		||||
    lodash.includes "^4.3.0"
 | 
			
		||||
    lodash.isboolean "^3.0.3"
 | 
			
		||||
    lodash.isinteger "^4.0.4"
 | 
			
		||||
    lodash.isnumber "^3.0.3"
 | 
			
		||||
    lodash.isplainobject "^4.0.6"
 | 
			
		||||
    lodash.isstring "^4.0.1"
 | 
			
		||||
    lodash.once "^4.0.0"
 | 
			
		||||
    ms "^2.1.1"
 | 
			
		||||
    semver "^5.6.0"
 | 
			
		||||
 | 
			
		||||
jsprim@^1.2.2:
 | 
			
		||||
  version "1.4.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
 | 
			
		||||
@@ -2231,6 +2321,23 @@ jsprim@^1.2.2:
 | 
			
		||||
    json-schema "0.2.3"
 | 
			
		||||
    verror "1.10.0"
 | 
			
		||||
 | 
			
		||||
jwa@^1.4.1:
 | 
			
		||||
  version "1.4.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
 | 
			
		||||
  integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    buffer-equal-constant-time "1.0.1"
 | 
			
		||||
    ecdsa-sig-formatter "1.0.11"
 | 
			
		||||
    safe-buffer "^5.0.1"
 | 
			
		||||
 | 
			
		||||
jws@^3.2.2:
 | 
			
		||||
  version "3.2.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
 | 
			
		||||
  integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    jwa "^1.4.1"
 | 
			
		||||
    safe-buffer "^5.0.1"
 | 
			
		||||
 | 
			
		||||
keyv@^3.0.0:
 | 
			
		||||
  version "3.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
 | 
			
		||||
@@ -2331,6 +2438,41 @@ locate-path@^6.0.0:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    p-locate "^5.0.0"
 | 
			
		||||
 | 
			
		||||
lodash.includes@^4.3.0:
 | 
			
		||||
  version "4.3.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
 | 
			
		||||
  integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=
 | 
			
		||||
 | 
			
		||||
lodash.isboolean@^3.0.3:
 | 
			
		||||
  version "3.0.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
 | 
			
		||||
  integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=
 | 
			
		||||
 | 
			
		||||
lodash.isinteger@^4.0.4:
 | 
			
		||||
  version "4.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
 | 
			
		||||
  integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=
 | 
			
		||||
 | 
			
		||||
lodash.isnumber@^3.0.3:
 | 
			
		||||
  version "3.0.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
 | 
			
		||||
  integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=
 | 
			
		||||
 | 
			
		||||
lodash.isplainobject@^4.0.6:
 | 
			
		||||
  version "4.0.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
 | 
			
		||||
  integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
 | 
			
		||||
 | 
			
		||||
lodash.isstring@^4.0.1:
 | 
			
		||||
  version "4.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
 | 
			
		||||
  integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
 | 
			
		||||
 | 
			
		||||
lodash.once@^4.0.0:
 | 
			
		||||
  version "4.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
 | 
			
		||||
  integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
 | 
			
		||||
 | 
			
		||||
lodash@4.17.21, lodash@^4.17.20, lodash@^4.17.21:
 | 
			
		||||
  version "4.17.21"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
 | 
			
		||||
@@ -3309,7 +3451,7 @@ retry@0.12.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
 | 
			
		||||
  integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
 | 
			
		||||
 | 
			
		||||
reusify@^1.0.4:
 | 
			
		||||
reusify@^1.0.0, reusify@^1.0.4:
 | 
			
		||||
  version "1.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
 | 
			
		||||
  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 | 
			
		||||
@@ -3410,7 +3552,7 @@ semver@7.3.5, semver@^7.3.2, semver@^7.3.4:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    lru-cache "^6.0.0"
 | 
			
		||||
 | 
			
		||||
semver@^5.3.0, semver@^5.7.1:
 | 
			
		||||
semver@^5.3.0, semver@^5.6.0, semver@^5.7.1:
 | 
			
		||||
  version "5.7.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
 | 
			
		||||
  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
 | 
			
		||||
@@ -3599,6 +3741,17 @@ static-extend@^0.1.1:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
 | 
			
		||||
  integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
 | 
			
		||||
 | 
			
		||||
steed@^1.1.3:
 | 
			
		||||
  version "1.1.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/steed/-/steed-1.1.3.tgz#f1525dd5adb12eb21bf74749537668d625b9abc5"
 | 
			
		||||
  integrity sha1-8VJd1a2xLrIb90dJU3Zo1iW5q8U=
 | 
			
		||||
  dependencies:
 | 
			
		||||
    fastfall "^1.5.0"
 | 
			
		||||
    fastparallel "^2.2.0"
 | 
			
		||||
    fastq "^1.3.0"
 | 
			
		||||
    fastseries "^1.7.0"
 | 
			
		||||
    reusify "^1.0.0"
 | 
			
		||||
 | 
			
		||||
strict-uri-encode@^2.0.0:
 | 
			
		||||
  version "2.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
 | 
			
		||||
@@ -4014,6 +4167,11 @@ v8flags@^3.2.0:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    homedir-polyfill "^1.0.1"
 | 
			
		||||
 | 
			
		||||
vary@^1.1.2:
 | 
			
		||||
  version "1.1.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
 | 
			
		||||
  integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
 | 
			
		||||
 | 
			
		||||
verror@1.10.0:
 | 
			
		||||
  version "1.10.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
 | 
			
		||||
@@ -4094,6 +4252,11 @@ xdg-basedir@^4.0.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
 | 
			
		||||
  integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
 | 
			
		||||
 | 
			
		||||
xtend@^4.0.0, xtend@^4.0.2:
 | 
			
		||||
  version "4.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
 | 
			
		||||
  integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
 | 
			
		||||
 | 
			
		||||
yallist@^3.0.0, yallist@^3.1.1:
 | 
			
		||||
  version "3.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user