Browse Source

working app

master
Lio 3 months ago
parent
commit
f5201efee4
13 changed files with 219 additions and 19 deletions
  1. +1
    -0
      .gitignore
  2. +9
    -0
      README.md
  3. +0
    -3
      config.ts
  4. +57
    -7
      index.ts
  5. +1
    -7
      middleware/db.ts
  6. +3
    -2
      middleware/index.ts
  7. +15
    -0
      middleware/lock.ts
  8. +6
    -0
      middleware/log.ts
  9. +42
    -0
      package-lock.json
  10. +2
    -0
      package.json
  11. +41
    -0
      utils/database.ts
  12. +39
    -0
      utils/generators.ts
  13. +3
    -0
      utils/index.ts

+ 1
- 0
.gitignore View File

@@ -1 +1,2 @@
node_modules/
config.ts

+ 9
- 0
README.md View File

@@ -0,0 +1,9 @@
# lio.click - Link Shortener

[Lio's](https://himbo.cat) personal link shortner.

won't add docs, if you want to host it yourself hmu

### Requirements

- CouchDB

+ 0
- 3
config.ts View File

@@ -1,3 +0,0 @@
export default {
port: 23842,
};

+ 57
- 7
index.ts View File

@@ -1,22 +1,72 @@
import Armpits from "@sniff/armpits";
import express from "express";
import { allowedNodeEnvironmentFlags } from "process";
import config from "./config";
import middleware from "./middleware/index";
import { CreateLink } from "./utils/database";
import { ErrorResponse } from "./utils/generators";
const app = express();

app.use(express.json());
app.use(middleware.database);
app.use(middleware.log);
app.get("/", async (req, res) => {
console.log(req.db.get("a"));
return res.json("a");
return res.redirect(301, config.mainDomain);
});

app.get("/all", async (req, res) => {
let links = [];

req.db.list({ include_docs: true }).then((body) => {
body.rows.forEach((row) => {
delete row.doc._id;
delete row.doc._rev;
links.push(row.doc);
});
res.json(links);
});
});

app.post("/", middleware.lock, async (req, res) => {
try {
let { target, code } = req.body;

if (!target)
return res
.status(400)
.send({ success: false, error: ErrorResponse("MISSING_TARGET") });

let Link = await CreateLink({ target, code });
return res.send(Link);
} catch (error) {
// console.error(error);
res.send({
success: false,
error: ErrorResponse(error.message),
});
}
});

app.get("/:slug", async (req, res) => {
app.get("/:code", async (req, res) => {
try {
let response = await req.db.get({ slug: req.params.slug });
} catch (error) {}
let response = await req.db.get(req.params.code);
res.redirect(301, response.target);
} catch (error) {
switch (error.message) {
case "missing":
return res.send({
success: false,
error: ErrorResponse("MISSING_CODE"),
});
default:
return res.send({ success: false, error: { msg: error } });
}
}
});

app.listen(config.port, () => {
Armpits.plus("Listening on port", config.port);
Armpits.plus(
`${config.domain.replace(/https?:\/\//, "")} | Listening on port`,
config.port
);
});

+ 1
- 7
middleware/db.ts View File

@@ -1,10 +1,4 @@
import Armpits from "@sniff/armpits";
const nano = require("nano")("https://admin:TokioAkari69@couchdb.lio.systems");
nano.db
.create("click")
.then((e) => Armpits.plus("Database created"))
.catch((e) => Armpits.minus("Database already exists"));
const click = nano.db.use("click");
import { click } from "../utils/database";
async function usedb(req, res, next) {
req.db = click;
next();


+ 3
- 2
middleware/index.ts View File

@@ -1,3 +1,4 @@
import database from "./db";

export default { database };
import log from "./log";
import lock from "./lock";
export default { database, log, lock };

+ 15
- 0
middleware/lock.ts View File

@@ -0,0 +1,15 @@
import config from "../config";

function lock(req, res, next) {
if (req.body.token !== config.token)
res.json({
success: false,
error: {
code: "AUTHENTICATION_NEEDED",
msg: "you're not authenticated, add a token to your request body",
},
});
else next();
}

export default lock;

+ 6
- 0
middleware/log.ts View File

@@ -0,0 +1,6 @@
import Armpits from "@sniff/armpits";
export default function log(req, res, next) {
delete req.body.token;
Armpits.info(`${req.method} Request to ${req.path} with data:`, req.body);
next();
}

+ 42
- 0
package-lock.json View File

@@ -50,6 +50,11 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"axios": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz",
@@ -116,6 +121,14 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
@@ -192,6 +205,11 @@
"ms": "2.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -211,6 +229,15 @@
"streamsearch": "0.1.2"
}
},
"discord-webhook-node": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/discord-webhook-node/-/discord-webhook-node-1.1.8.tgz",
"integrity": "sha512-3u0rrwywwYGc6HrgYirN/9gkBYqmdpvReyQjapoXARAHi0P0fIyf3W5tS5i3U3cc7e44E+e7dIHYUeec7yWaug==",
"requires": {
"form-data": "^3.0.0",
"node-fetch": "^2.6.0"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -287,6 +314,16 @@
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
"integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA=="
},
"form-data": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
"integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@@ -464,6 +501,11 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",


+ 2
- 0
package.json View File

@@ -6,9 +6,11 @@
"dependencies": {
"@sniff/armpits": "0.0.3",
"chalk": "^4.1.0",
"discord-webhook-node": "^1.1.8",
"express": "^4.17.1",
"loggaby": "^3.0.1",
"lowdb": "^1.0.0",
"minimist": "^1.2.5",
"multer": "^1.4.2",
"nano": "^9.0.0",
"nanoid": "^3.1.16"


+ 41
- 0
utils/database.ts View File

@@ -0,0 +1,41 @@
import { RandomString as string } from "./generators";
import Armpits from "@sniff/armpits";
import config from "../config";
const nano = require("nano")(config.nano);
nano.db
.create("click")
.then((e) => Armpits.plus("Database created"))
.catch((e) => Armpits.minus("Database already exists"));
export const click = nano.db.use("click");

var exists = async function (id) {
return await click
.head(id)
.then((r) => {
return true;
})
.catch((e) => {
return false;
});
};
export async function CreateLink({
target,
code,
}: {
code?: string;
target: string;
}): Promise<{ code: string; target: string }> {
if (!code) code = string(5, { chars: false, lower: true });

let checkExists = await exists(code);
if (checkExists) throw new Error("CODE_EXISTS");
else
await click
.insert({ target, code }, code)
.then((e) => Armpits.plus(`Link/${code} created for ${target}`));

return {
code,
target,
};
}

+ 39
- 0
utils/generators.ts View File

@@ -0,0 +1,39 @@
function RandomString(
length: number,
options: { chars: boolean; lower: boolean } = { chars: true, lower: false }
): string {
let text = "";
let possible = "";
if (!options.lower) possible += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
possible += "abcdefghijklmnopqrstuvwxyz0123456789";
if (options.chars) possible += "-_+%!";

for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}

return text;
}
let CODES = {
MISSING_TARGET: {
code: "MISSING_TARGET",
msg: "you forgot to include a target url",
},
INVALID_TARGET: {
code: "INVALID_TARGET",
msg: "something in your target was invalid, please check ",
},
MISSING_CODE: {
code: "MISSING_CODE",
msg: "the shortlink you're trying to access does not exist.",
},
CODE_EXISTS: {
code: "CODE_EXISTS",
msg: "the shortlink you're trying to create already exists",
},
};
function ErrorResponse(code) {
return CODES[code];
}

export { RandomString, ErrorResponse };

+ 3
- 0
utils/index.ts View File

@@ -0,0 +1,3 @@
import { RandomString, ErrorResponse } from "./generators";

export { RandomString as string, ErrorResponse as error };

Loading…
Cancel
Save