diff --git a/src/app.js b/src/app.js index cfac678..c22fe65 100644 --- a/src/app.js +++ b/src/app.js @@ -20,6 +20,8 @@ async function init() { await MiddleWare.RateLimits.init(); Logger.ready(); + + // Logger.debug(JSON.stringify(await Database.users.getUserByID(12341356), null, 4)); // Logger.debug(JSON.stringify(await Database.users.listAll(), null, 4)); diff --git a/src/controllers/index.js b/src/controllers/index.js index fd4ef07..43a6645 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -2,3 +2,4 @@ export let Controllers = {}; Controllers.UserController = require('./userController').UserController; Controllers.LoginController = require('./loginController').LoginController; +Controllers.PermaLinkController = require('./permaLinkController').PermaLinkController; diff --git a/src/controllers/middleware/rateLimits.js b/src/controllers/middleware/rateLimits.js index c376d79..5193345 100644 --- a/src/controllers/middleware/rateLimits.js +++ b/src/controllers/middleware/rateLimits.js @@ -5,15 +5,14 @@ let requestsPerSecond = 2; // let disposeTime = 20000; //ms 1800000 = 30 mins let buckets = {} -export class RateLimits extends MiddleWare{ +export class RateLimits extends MiddleWare { static async request(req, res, next) { let ip = req.connection.remoteAddress; + MiddleWare.analytics(req, res, next); if (!buckets[ip]) { Logger.debug(`New rate limiting bucket`); RateLimits.newBucket(ip); - - MiddleWare.analytics(req, res, next); return; } @@ -26,7 +25,6 @@ export class RateLimits extends MiddleWare{ } buckets[ip].tokens.pop(); - MiddleWare.analytics(req, res, next); } static newBucket(ip) { diff --git a/src/controllers/permaLinkController.js b/src/controllers/permaLinkController.js new file mode 100644 index 0000000..c2cdd87 --- /dev/null +++ b/src/controllers/permaLinkController.js @@ -0,0 +1,52 @@ +import {Logger} from '../models/logger'; +import {ControllerHandler} from './controllerHandler'; +import {API} from '../models/api/api'; +import {Database} from '../models/database/database' +import {PermaLink} from '../models/permalinks/permalink'; + +export class PermaLinkController extends ControllerHandler { + static async unauthentacatedPermaLink(req, res, next) { + let errors = new API.errors(res); + + let text = req.body.text || undefined; + if (!text) { + errors.addError(422, 'Unprocessable entity', 'There is no text'); + errors.endpoint(); + next(); + return; + } + + let uid = await PermaLink.genUID() || new Date().getTime(); + let endpoint = await PermaLink.genEndpoint(); + + let success = await Database.permalink.newNote(uid, endpoint, text); + + if (success == -1) { + errors.addError(500, 'Internal server error'); + errors.endpoint(); + next(); + return; + } + + new API.permalink(res, text, uid, endpoint).endpoint(); + next(); + } + + static async getNote(req, res, next) { + let endpoint = req.params.endpoint || undefined; + + if (!endpoint) { + next(); + return; + } + + let data = await Database.permalink.getNoteByEndpoint(endpoint); + if (data == -1) { + next(); + return; + } + + res.end(data.text); + next(); + } +} diff --git a/src/controllers/routes/router.js b/src/controllers/routes/router.js index babf572..70960d8 100644 --- a/src/controllers/routes/router.js +++ b/src/controllers/routes/router.js @@ -19,8 +19,8 @@ export class Router { app.post('/user', [MiddleWare.RateLimits.request, Controllers.UserController.newUser]); app.post('/login', [MiddleWare.RateLimits.request, Controllers.LoginController.authenticate]); - app.post('permanote', [MiddleWare.RateLimits]); - + app.post('/unauth/permanote', [MiddleWare.RateLimits.request, Controllers.PermaLinkController.unauthentacatedPermaLink]); + app.get('/note/:endpoint', [MiddleWare.RateLimits.request, Controllers.PermaLinkController.getNote]); app.get('*', [MiddleWare.RateLimits.request, StatusCodes.pageNotFound]); Logger.info('HTTP endpoints settup'); diff --git a/src/models/api/API.js b/src/models/api/API.js index 88ba461..1f68ead 100644 --- a/src/models/api/API.js +++ b/src/models/api/API.js @@ -8,3 +8,4 @@ export class API extends BaseAPI { API.errors = require('./APIErrors').APIErrors; API.user = require('./userResponses').UserAPI; +API.permalink = require('./permaLinkResponse').PermaLinkAPI; diff --git a/src/models/api/permaLinkResponse.js b/src/models/api/permaLinkResponse.js new file mode 100644 index 0000000..034de55 --- /dev/null +++ b/src/models/api/permaLinkResponse.js @@ -0,0 +1,33 @@ +import {API} from './API'; +import {PermaLink} from '../../models/permalinks/permalink'; + +export class PermaLinkAPI extends API { + constructor(res, text, uid, endpoint, username, id) { + super(); + this.res = res; + this.response = { + status: { + error: false, + code: 201, + type: 'created', + message: 'Success' + }, + data: [ + { + status: 'Resource created', + note: { + uid: uid, + endpoint: `/api/note/${endpoint}`, + text: text, + createdby: username, + id: id + }, + } + ] + } + } + + endpoint() { + this.res.status(201).end(JSON.stringify(this.response, false, 4)); + } +} diff --git a/src/models/database/baseDatabase.js b/src/models/database/baseDatabase.js index 496d954..75d83d9 100644 --- a/src/models/database/baseDatabase.js +++ b/src/models/database/baseDatabase.js @@ -7,11 +7,13 @@ let connection; let User; let Auth; +let PermaNote; export class BaseDatabase { static get Connection() {return connection;} static get User() {return User} static get Auth() {return Auth} + static get PermaNote() {return PermaNote} static async init() { Logger.info('Connecting to SQLite Database'); @@ -54,6 +56,20 @@ export class BaseDatabase { tableName: `auth` }); + PermaNote = connection.define('permanote', { + uid: { + type: Sequelize.BIGINT, + primaryKey: true, + unique: true + }, + endpoint: Sequelize.TEXT, + text: Sequelize.TEXT, + creatorid: { + type: Sequelize.BIGINT, + allowNull: true + } + }); + try { await connection.sync({force: false}); } catch (e) { diff --git a/src/models/database/database.js b/src/models/database/database.js index 7947242..05690ad 100644 --- a/src/models/database/database.js +++ b/src/models/database/database.js @@ -29,3 +29,4 @@ export class Database extends BaseDatabase { Database.users = require('./users').UserTools; Database.auth = require('./tokens').TokenTools; +Database.permalink = require('./permaLink').PermaLinkTools; diff --git a/src/models/database/permaLink.js b/src/models/database/permaLink.js new file mode 100644 index 0000000..76b02fb --- /dev/null +++ b/src/models/database/permaLink.js @@ -0,0 +1,56 @@ +import Sequelize from 'sequelize'; + +import {BaseDatabase} from './baseDatabase'; +import {Logger} from '../logger'; + +export class PermaLinkTools extends BaseDatabase { + static async listAll() { + let PermaNote = BaseDatabase.PermaNote; + return PermaNote.findAll(); + } + + static async newNote(uid, endpoint, text, id) { + let PermaNote = BaseDatabase.PermaNote; + + id = id || null; + + try { + let note = await PermaNote.create({ + uid: uid, + endpoint: endpoint, + text: text, + creatorid: id + }); + return note; + } catch (e) { + Logger.error(`An error occured while inserting user a note with the endpoint ${endpoint} into permanote table: ${e}`); + return -1; + } + } + + static async getNoteByUID(uid) { + let PermaNote = BaseDatabase.PermaNote; + + try { + let note = await PermaNote.findOne({where: {uid: uid}}); + if (note == null) return -1; + return note; + } catch (e) { + Logger.error(`An error occured while querying for a permanote by uid ${uid}: ${e}`); + return -1; + } + } + + static async getNoteByEndpoint(endpoint) { + let PermaNote = BaseDatabase.PermaNote; + + try { + let note = await PermaNote.findOne({where: {endpoint: endpoint}}); + if (note == null) return -1; + return note; + } catch (e) { + Logger.error(`An error occured while querying for a permanote by endpoint ${endpoint}: ${e}`); + return -1; + } + } +} \ No newline at end of file diff --git a/src/models/database/sqlite/database.sqlite b/src/models/database/sqlite/database.sqlite index 786de92..fee526b 100644 Binary files a/src/models/database/sqlite/database.sqlite and b/src/models/database/sqlite/database.sqlite differ diff --git a/src/models/permalinks/permalink.js b/src/models/permalinks/permalink.js new file mode 100644 index 0000000..752c78f --- /dev/null +++ b/src/models/permalinks/permalink.js @@ -0,0 +1,23 @@ +import {Database} from '../database/database'; + +export class PermaLink { + static async genUID() { + return new Date().getTime(); + } + + static async genEndpoint() { + const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + let endpoint; + while (true) { + endpoint = 'N'; + for (let i = 0; i < 7; i++) + endpoint += possible[Math.floor(Math.random() * possible.length)]; + + if (await Database.permalink.getNoteByEndpoint(endpoint) == -1) + break; + } + + return endpoint; + } +}