Compare commits
	
		
			49 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 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 | ||||
| ENABLE_REGISTER=true | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -58,7 +58,6 @@ jspm_packages/ | ||||
| .yarn/build-state.yml | ||||
| .yarn/install-state.gz | ||||
| .pnp.* | ||||
| yarn.lock | ||||
| package-lock.json | ||||
|  | ||||
| *.sqlite* | ||||
							
								
								
									
										106
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,11 +2,117 @@ | ||||
|  | ||||
| All notable changes to this project will be documented in this file. Dates are displayed in UTC. | ||||
|  | ||||
| #### [0.5.0](https://git.odit.services/kauft.es/linkylinky/compare/0.4.3...0.5.0) | ||||
|  | ||||
| - 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) | ||||
|  | ||||
| > 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 | ||||
|  | ||||
| > 14 August 2021 | ||||
|  | ||||
| - 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) | ||||
| - 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) | ||||
| - 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) | ||||
|   | ||||
							
								
								
									
										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 . | ||||
| 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 | ||||
| EXPOSE 3000 | ||||
|  | ||||
| WORKDIR /app | ||||
|  | ||||
| COPY migrations ./migrations | ||||
| COPY src/server.js ./ | ||||
| COPY knexfile.js ./ | ||||
|  | ||||
| CMD ["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) { | ||||
|    | ||||
| }; | ||||
							
								
								
									
										26
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,20 +1,36 @@ | ||||
| { | ||||
|   "name": "@odit/shortener-backend", | ||||
|   "version": "0.0.2", | ||||
|   "version": "0.5.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", | ||||
|     "knex": "^0.21.21", | ||||
|     "sqlite3": "^5.0.2", | ||||
|     "uniqid": "^5.3.0" | ||||
| @@ -28,6 +44,12 @@ | ||||
|       "commit": true, | ||||
|       "requireCleanWorkingDir": false, | ||||
|       "commitMessage": "🚀RELEASE ${version}", | ||||
|       "git.commitArgs": [ | ||||
|         "-S" | ||||
|       ], | ||||
|       "git.tagArgs": [ | ||||
|         "-S" | ||||
|       ], | ||||
|       "push": true, | ||||
|       "tag": true, | ||||
|       "tagName": null, | ||||
|   | ||||
							
								
								
									
										179
									
								
								src/server.js
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								src/server.js
									
									
									
									
									
								
							| @@ -6,8 +6,10 @@ const argon2 = require('argon2'); | ||||
| 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 +17,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 | ||||
| @@ -56,7 +111,7 @@ fastify.get('/:shortcode', async (req, res) => { | ||||
|         return 404 | ||||
|     } | ||||
|     res.redirect(302, target[0].target); | ||||
|     await knex('visits').insert({ shortcode }); | ||||
|     await knex('visits').insert({ shortcode, provider: 'native' }); | ||||
| }) | ||||
|  | ||||
| //Create new url schema | ||||
| @@ -133,6 +188,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 | ||||
| fastify.get('/api/:shortcode', async (req, res) => { | ||||
|     const shortcode = req.params.shortcode; | ||||
| @@ -162,8 +231,9 @@ fastify.get('/api/:shortcode', async (req, res) => { | ||||
|     } | ||||
| }); | ||||
|  | ||||
|  | ||||
| //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 +265,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) => { | ||||
|     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,15 +276,7 @@ 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); | ||||
|  | ||||
| @@ -221,7 +284,7 @@ fastify.after(() => { | ||||
|     }); | ||||
|  | ||||
|     //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 +300,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') | ||||
|             .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 +386,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 +395,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 +423,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) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user