Compare commits

...

3 Commits

Author SHA1 Message Date
eb96408d33
Working clientside stuff
All checks were successful
continuous-integration/drone/push Build is passing
closes #3
2021-09-25 18:45:52 +02:00
11bd1b4f1f
Added 'clientside' flag to getters and setters 2021-09-25 18:28:49 +02:00
e3214084f6
Added migration for clientside redirects
ref #3
2021-09-25 18:25:53 +02:00
2 changed files with 307 additions and 33 deletions

View File

@ -0,0 +1,9 @@
exports.up = function(knex) {
return knex.schema.table('urls', function (table) {
table.boolean('clientside').defaultTo(false);
});
};
exports.down = function(knex) {
};

View File

@ -104,7 +104,7 @@ fastify.get('/:shortcode', async (req, res) => {
if (!shortcode) { if (!shortcode) {
return 404; return 404;
} }
const target = await knex.select('target', 'no_preview') const target = await knex.select('target', 'no_preview', 'clientside')
.from('urls') .from('urls')
.where('shortcode', '=', shortcode) .where('shortcode', '=', shortcode)
.limit(1); .limit(1);
@ -113,33 +113,13 @@ fastify.get('/:shortcode', async (req, res) => {
} }
if (isBot(req.headers['user-agent']) && target[0].no_preview) { if (isBot(req.headers['user-agent']) && target[0].no_preview) {
return ` res.type("text/html");
<!DOCTYPE html> return bot_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> if (target[0].clientside) {
</head> res.type("text/html");
<body> return clientside_html.replace("{{targeturl}}", target[0].target)
<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); res.redirect(302, target[0].target);
@ -154,6 +134,7 @@ const newUrlSchema = {
target: { type: 'string' }, target: { type: 'string' },
shortcode: { type: 'string' }, shortcode: { type: 'string' },
no_preview: { type: 'boolean' }, no_preview: { type: 'boolean' },
clientside: { type: 'boolean' }
} }
} }
}; };
@ -163,6 +144,7 @@ fastify.post('/api', { newUrlSchema }, async (req, res) => {
const target = req.body?.target; const target = req.body?.target;
let shortcode = req.body?.shortcode; let shortcode = req.body?.shortcode;
let no_preview = req.body?.no_preview || false; let no_preview = req.body?.no_preview || false;
let clientside = req.body?.clientside || false;
//Check if the user provided a target //Check if the user provided a target
if (!target) { if (!target) {
@ -182,7 +164,7 @@ fastify.post('/api', { newUrlSchema }, async (req, res) => {
return response; return response;
} }
} }
const exists = await knex.select('shortcode', 'no_preview') const exists = await knex.select('shortcode', 'no_preview', 'clientside')
.from('urls') .from('urls')
.where('target', '=', target) .where('target', '=', target)
.limit(1); .limit(1);
@ -192,7 +174,8 @@ fastify.post('/api', { newUrlSchema }, async (req, res) => {
url: `${config.getBaseUrl()}/${shortcode}`, url: `${config.getBaseUrl()}/${shortcode}`,
shortcode, shortcode,
target, target,
no_preview: exists[0].no_preview no_preview: exists[0].no_preview,
clientside: exists[0].clientside
} }
} }
shortcode = uniqid(); shortcode = uniqid();
@ -214,13 +197,14 @@ fastify.post('/api', { newUrlSchema }, async (req, res) => {
} }
//Create a new db entry //Create a new db entry
await knex('urls').insert({ target, shortcode, no_preview }); await knex('urls').insert({ target, shortcode, no_preview, clientside });
return { return {
url: `${config.getBaseUrl()}/${shortcode}`, url: `${config.getBaseUrl()}/${shortcode}`,
shortcode, shortcode,
target, target,
no_preview no_preview,
clientside
} }
}); });
@ -247,7 +231,7 @@ fastify.get('/api/:shortcode', async (req, res) => {
return 404; return 404;
} }
const exists = await knex.select('shortcode', 'target', 'no_preview') const exists = await knex.select('shortcode', 'target', 'no_preview', 'clientside')
.from('urls') .from('urls')
.where('shortcode', '=', shortcode) .where('shortcode', '=', shortcode)
.limit(1); .limit(1);
@ -264,6 +248,7 @@ fastify.get('/api/:shortcode', async (req, res) => {
shortcode: exists[0].shortcode, shortcode: exists[0].shortcode,
target: exists[0].target, target: exists[0].target,
no_preview: exists[0].no_preview, no_preview: exists[0].no_preview,
clientside: exists[0].clientside,
visits: visits.length visits: visits.length
} }
}); });
@ -350,7 +335,7 @@ fastify.after(() => {
//Get all urls api route //Get all urls api route
fastify.get('/api', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, res) => { fastify.get('/api', { onRequest: fastify.auth([fastify.basicAuth, fastify.verifyJWT]) }, async (req, res) => {
urls = await knex.select('target', 'shortcode', 'no_preview') urls = await knex.select('target', 'shortcode', 'no_preview', 'clientside')
.from('urls'); .from('urls');
for (let url of urls) { for (let url of urls) {
@ -474,6 +459,286 @@ async function validate(username, password, req, reply) {
req.user = username; req.user = username;
} }
const bot_html = `<!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>
`;
const clientside_html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="robot" content="no-index">
</head>
<body>
<style>
body {
background: black;
overflow: hidden;
}
.containCube {
position: relative;
height: 100vh;
width: 100%;
perspective: 800px;
}
.containCube .cube {
position: absolute;
height: 300px;
width: 300px;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
box-sizing: border-box;
transform-style: preserve-3d;
transform-origin: 50% 50%;
-webkit-animation: rotate 20s ease-in-out infinite alternate;
animation: rotate 20s ease-in-out infinite alternate;
}
.containCube .cubeGroup {
position: absolute;
display: grid;
box-sizing: border-box;
height: 100%;
width: 100%;
color: white;
text-shadow: 0 0 1px black;
border: 3px dashed white;
}
.containCube .cubeGroup h1 {
margin: auto;
}
.containCube .cube-front {
transform: translatez(150px);
}
.containCube .cube-rear {
transform: translatez(-150px) rotatey(180deg);
}
.containCube .cube-right {
transform-origin: 100%;
transform: rotatey(90deg) translatex(150px);
}
.containCube .cube-left {
transform-origin: 0%;
transform: rotatey(-90deg) translatex(-150px);
}
.containCube .cube-bottom {
transform-origin: 50% 100%;
transform: rotatex(-90deg) translatey(150px);
}
.containCube .cube-top {
transform-origin: 50% 0%;
transform: rotatex(90deg) translatey(-150px);
}
.containCube .cube-1 {
background: red;
}
.containCube .cube-2 {
background: red;
}
.containCube .cube-3 {
background: red;
}
.containCube .cube-4 {
background: red;
}
.containCube .cube-5 {
background: red;
}
.containCube .cube-6 {
background: red;
}
@-webkit-keyframes rotate {
10% {
transform: rotate3d(1, 1, 0, 320deg);
}
20% {
transform: rotate3d(1, 0, 0, -90deg);
}
30% {
transform: rotate3d(1, 1, 0, 440deg);
}
40% {
transform: rotate3d(1, 0, 0, -180deg);
}
50% {
transform: rotate3d(1, 1, 0, 460deg);
}
60% {
transform: rotate3d(0, 1, 0, -195deg);
}
70% {
transform: rotate3d(1, 1, 0, 172deg);
}
80% {
transform: rotate3d(0, 1, 0, -360deg);
}
90% {
transform: rotate3d(1, 1, 0, 280deg);
}
}
@keyframes rotate {
10% {
transform: rotate3d(1, 1, 0, 320deg);
}
20% {
transform: rotate3d(1, 0, 0, -90deg);
}
30% {
transform: rotate3d(1, 1, 0, 440deg);
}
40% {
transform: rotate3d(1, 0, 0, -180deg);
}
50% {
transform: rotate3d(1, 1, 0, 460deg);
}
60% {
transform: rotate3d(0, 1, 0, -195deg);
}
70% {
transform: rotate3d(1, 1, 0, 172deg);
}
80% {
transform: rotate3d(0, 1, 0, -360deg);
}
90% {
transform: rotate3d(1, 1, 0, 280deg);
}
}
@-webkit-keyframes rotateZed {
20% {
transform: translatez(100px);
}
40% {
transform: translatez(-100px);
}
60% {
transform: translatez(100px);
}
80% {
transform: translatez(-100px);
}
}
@keyframes rotateZed {
20% {
transform: translatez(100px);
}
40% {
transform: translatez(-100px);
}
60% {
transform: translatez(100px);
}
80% {
transform: translatez(-100px);
}
}
</style>
<div class="containCube">
<div class="cube">
<div class="cubeGroup cube-front cube-1">
<h1>kauft.es</h1>
</div>
<div class="cubeGroup cube-top cube-2">
<h1>kauft.es</h1>
</div>
<div class="cubeGroup cube-left cube-3">
<h1>kauft.es</h1>
</div>
<div class="cubeGroup cube-right cube-4">
<h1>kauft.es</h1>
</div>
<div class="cubeGroup cube-rear cube-5">
<h1>kauft.es</h1>
</div>
<div class="cubeGroup cube-bottom cube-6">
<h1>kauft.es</h1>
</div>
</div>
</div>
<script>
setTimeout(function () {
location.replace("{{targeturl}}");
}, 3000);//Delay 3 seconds
</script>
</body>
</html>
`;
// Run the server! // Run the server!
const start = async () => { const start = async () => {
try { try {