forked from engineering/cloudservices
fixes
parent
7d5b56d8cc
commit
8c12ad4086
|
@ -57,6 +57,8 @@ export default class Root extends Route {
|
|||
try {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
const token = <any> jwt.verify(req.query.t.toString(), this.server.client.config.keyPair.privateKey);
|
||||
const check = await this.server.storage.get<boolean>(token);
|
||||
if (!check) return res.sendStatus(401);
|
||||
const embed = new RichEmbed();
|
||||
embed.setTitle('Referral Authorization');
|
||||
embed.addField('Referred User', token.referredUserAndDiscrim, true);
|
||||
|
@ -64,6 +66,7 @@ export default class Root extends Route {
|
|||
embed.addField('Referral Code', token.referralCode, true);
|
||||
const channel = <TextChannel> this.server.client.guilds.get('446067825673633794').channels.get('580950455581147146');
|
||||
res.sendStatus(200);
|
||||
await this.server.storage.set(token, true);
|
||||
return channel.createMessage({ content: `<@${token.staffUserID}>`, embed });
|
||||
} catch {
|
||||
return res.sendStatus(401);
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
if (response.status === 200) return alert('Request authorized. You may now close this tab.');
|
||||
if (response.status === 401) return alert('Authorization Token incorrect, try again.');
|
||||
if (response.status >= 500) return alert('INTERNAL SERVER ERROR');
|
||||
alert('Authentication Complete.');
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/* eslint-disable no-constant-condition */
|
||||
import { promises as fs, accessSync, constants, writeFileSync } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
import { gzip, gzipSync, unzip } from 'zlib';
|
||||
|
||||
type JSONData = [{key: string, value: any}?];
|
||||
|
||||
|
||||
/**
|
||||
* Persistant local JSON-based storage.
|
||||
* - auto-locking system to prevent corrupted data
|
||||
* - uses gzip compression to keep DB storage space utilization low
|
||||
* @author Matthew <matthew@staff.libraryofcode.org>
|
||||
*/
|
||||
export default class LocalStorage {
|
||||
protected readonly storagePath: string;
|
||||
|
||||
protected locked: boolean = false;
|
||||
|
||||
constructor(dbName: string, dir = `${__dirname}/../../localstorage`) {
|
||||
this.storagePath = `${dir}/${dbName}.json.gz`;
|
||||
this.init();
|
||||
}
|
||||
|
||||
private init() {
|
||||
try {
|
||||
accessSync(this.storagePath, constants.F_OK);
|
||||
} catch {
|
||||
const setup = [];
|
||||
const data = gzipSync(JSON.stringify(setup));
|
||||
writeFileSync(this.storagePath, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses data using gzip.
|
||||
* @param data The data to be compressed.
|
||||
* ```ts
|
||||
* await LocalStorage.compress('hello!');
|
||||
* ```
|
||||
*/
|
||||
static async compress(data: string): Promise<Buffer> {
|
||||
const func = promisify(gzip);
|
||||
const comp = <Buffer> await func(data);
|
||||
return comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompresses data using gzip.
|
||||
* @param data The data to be decompressed.
|
||||
* ```ts
|
||||
* const compressed = await LocalStorage.compress('data');
|
||||
* const decompressed = await LocalStorage.decompress(compressed);
|
||||
* console.log(decompressed); // logs 'data';
|
||||
* ```
|
||||
*/
|
||||
static async decompress(data: Buffer): Promise<string> {
|
||||
const func = promisify(unzip);
|
||||
const uncomp = <Buffer> await func(data);
|
||||
return uncomp.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves one data from the store.
|
||||
* If the store has multiple entries for the same key, this function will only return the first entry.
|
||||
* ```ts
|
||||
* await LocalStorage.get<type>('data-key');
|
||||
* ```
|
||||
* @param key The key for the data entry.
|
||||
*/
|
||||
public async get<T>(key: string): Promise<T> {
|
||||
while (true) {
|
||||
if (!this.locked) break;
|
||||
}
|
||||
this.locked = true;
|
||||
|
||||
const file = await fs.readFile(this.storagePath);
|
||||
const uncomp = await LocalStorage.decompress(file);
|
||||
this.locked = false;
|
||||
const json: JSONData = JSON.parse(uncomp);
|
||||
const result = json.filter((data) => data.key === key);
|
||||
if (!result[0]) return null;
|
||||
return result[0].value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves multiple data keys/values from the store.
|
||||
* This function will return all of the values matching the key you provided exactly. Use `LocalStorage.get();` if possible.
|
||||
* ```ts
|
||||
* await LocalStorage.get<type>('data-key');
|
||||
* @param key The key for the data entry.
|
||||
*/
|
||||
public async getMany<T>(key: string): Promise<{key: string, value: T}[]> {
|
||||
while (true) {
|
||||
if (!this.locked) break;
|
||||
}
|
||||
this.locked = true;
|
||||
|
||||
const file = await fs.readFile(this.storagePath);
|
||||
const uncomp = await LocalStorage.decompress(file);
|
||||
this.locked = false;
|
||||
const json: JSONData = JSON.parse(uncomp);
|
||||
const result = json.filter((data) => data.key === key);
|
||||
if (result.length < 1) return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a key/value pair and creates a new data entry.
|
||||
* @param key The key for the data entry.
|
||||
* @param value The value for the data entry, can be anything that is valid JSON.
|
||||
* @param options.override [DEPRECATED] By default, this function will error if the key you're trying to set already exists. Set this option to true to override that setting.
|
||||
* ```ts
|
||||
* await LocalStorage.set('data-key', 'test');
|
||||
* ```
|
||||
*/
|
||||
public async set(key: string, value: any): Promise<void> {
|
||||
while (true) {
|
||||
if (!this.locked) break;
|
||||
}
|
||||
this.locked = true;
|
||||
|
||||
const file = await fs.readFile(this.storagePath);
|
||||
const uncomp = await LocalStorage.decompress(file);
|
||||
const json: JSONData = JSON.parse(uncomp);
|
||||
json.push({ key, value });
|
||||
const comp = await LocalStorage.compress(JSON.stringify(json));
|
||||
await fs.writeFile(this.storagePath, comp);
|
||||
this.locked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the data for the specified key.
|
||||
* **Warning:** This function will delete ALL matching entries.
|
||||
* ```ts
|
||||
* await LocalStorage.del('data-key');
|
||||
* ```
|
||||
* @param key The key for the data entry.
|
||||
*/
|
||||
public async del(key: string): Promise<void> {
|
||||
while (true) {
|
||||
if (!this.locked) break;
|
||||
}
|
||||
this.locked = true;
|
||||
|
||||
const file = await fs.readFile(this.storagePath);
|
||||
const uncomp = await LocalStorage.decompress(file);
|
||||
const json: JSONData = JSON.parse(uncomp);
|
||||
const filtered = json.filter((data) => data.key !== key);
|
||||
const comp = await LocalStorage.compress(JSON.stringify(filtered));
|
||||
await fs.writeFile(this.storagePath, comp);
|
||||
this.locked = false;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ import express from 'express';
|
|||
import bodyParser from 'body-parser';
|
||||
import helmet from 'helmet';
|
||||
import fs from 'fs-extra';
|
||||
import { Client, Collection, Route } from '.';
|
||||
import { Client, Collection, LocalStorage, Route } from '.';
|
||||
import { Security } from '../api';
|
||||
|
||||
|
||||
|
@ -16,6 +16,8 @@ export default class Server {
|
|||
|
||||
public app: express.Express;
|
||||
|
||||
public storage: LocalStorage;
|
||||
|
||||
public options: { port: number }
|
||||
|
||||
constructor(client: Client, options?: { port: number }) {
|
||||
|
@ -24,6 +26,7 @@ export default class Server {
|
|||
this.client = client;
|
||||
this.security = new Security(this.client);
|
||||
this.app = express();
|
||||
this.storage = new LocalStorage('usedra', '/opt/CloudServices/localstorage');
|
||||
this.connect();
|
||||
this.loadRoutes();
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ export { default as Client } from './Client';
|
|||
export { default as Collection } from './Collection';
|
||||
export { default as Command } from './Command';
|
||||
export { default as Event } from './Event';
|
||||
export { default as LocalStorage } from './LocalStorage';
|
||||
export { default as RichEmbed } from './RichEmbed';
|
||||
export { default as Route } from './Route';
|
||||
export { default as Security } from './Security';
|
||||
|
|
Loading…
Reference in New Issue