mirror of
https://github.com/mollersuite/monofile.git
synced 2024-11-21 21:36:26 -08:00
Merge pull request #14 from nbitzz/btr-inline-docs
Better inline documentation
This commit is contained in:
commit
bf2b398a1a
|
@ -27,6 +27,14 @@ export interface Account {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Create a new account.
|
||||||
|
* @param username New account's username
|
||||||
|
* @param pwd New account's password
|
||||||
|
* @param admin Whether or not the account should have administrative rights
|
||||||
|
* @returns A Promise which returns the new account's ID
|
||||||
|
*/
|
||||||
|
|
||||||
export function create(username:string,pwd:string,admin:boolean=false):Promise<string> {
|
export function create(username:string,pwd:string,admin:boolean=false):Promise<string> {
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
let accId = crypto.randomBytes(12).toString("hex")
|
let accId = crypto.randomBytes(12).toString("hex")
|
||||||
|
@ -46,26 +54,52 @@ export function create(username:string,pwd:string,admin:boolean=false):Promise<s
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Gets an account from its username.
|
||||||
|
* @param id The target account's username
|
||||||
|
* @returns An Account, if it exists
|
||||||
|
*/
|
||||||
export function getFromUsername(username:string) {
|
export function getFromUsername(username:string) {
|
||||||
return Accounts.find(e => e.username == username)
|
return Accounts.find(e => e.username == username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Gets an account from its ID.
|
||||||
|
* @param id The target account's ID
|
||||||
|
* @returns An Account, if it exists
|
||||||
|
*/
|
||||||
export function getFromId(id:string) {
|
export function getFromId(id:string) {
|
||||||
return Accounts.find(e => e.id == id)
|
return Accounts.find(e => e.id == id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Gets an account from an AuthToken. Equivalent to getFromId(auth.validate(token)).
|
||||||
|
* @param token A valid AuthToken
|
||||||
|
* @returns An Account, if the token is valid
|
||||||
|
*/
|
||||||
export function getFromToken(token:string) {
|
export function getFromToken(token:string) {
|
||||||
let accId = auth.validate(token)
|
let accId = auth.validate(token)
|
||||||
if (!accId) return
|
if (!accId) return
|
||||||
return getFromId(accId)
|
return getFromId(accId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Deletes an account.
|
||||||
|
* @param id The target account's ID
|
||||||
|
*/
|
||||||
export function deleteAccount(id:string) {
|
export function deleteAccount(id:string) {
|
||||||
Accounts.splice(Accounts.findIndex(e => e.id == id),1)
|
Accounts.splice(Accounts.findIndex(e => e.id == id),1)
|
||||||
return save()
|
return save()
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace password {
|
export namespace password {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Generates a hashed and salted version of an input password.
|
||||||
|
* @param password Target password.
|
||||||
|
* @param _salt Designated password salt. Use to validate a password.
|
||||||
|
*/
|
||||||
|
|
||||||
export function hash(password:string,_salt?:string) {
|
export function hash(password:string,_salt?:string) {
|
||||||
let salt = _salt || crypto.randomBytes(12).toString('base64')
|
let salt = _salt || crypto.randomBytes(12).toString('base64')
|
||||||
let hash = crypto.createHash('sha256').update(`${salt}${password}`).digest('hex')
|
let hash = crypto.createHash('sha256').update(`${salt}${password}`).digest('hex')
|
||||||
|
@ -76,6 +110,12 @@ export namespace password {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Sets an account's password.
|
||||||
|
* @param id The target account's ID
|
||||||
|
* @param password New password
|
||||||
|
*/
|
||||||
|
|
||||||
export function set(id:string,password:string) {
|
export function set(id:string,password:string) {
|
||||||
let acc = Accounts.find(e => e.id == id)
|
let acc = Accounts.find(e => e.id == id)
|
||||||
if (!acc) return
|
if (!acc) return
|
||||||
|
@ -84,6 +124,12 @@ export namespace password {
|
||||||
return save()
|
return save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Tests a password against an account.
|
||||||
|
* @param id The target account's ID
|
||||||
|
* @param password Password to check
|
||||||
|
*/
|
||||||
export function check(id:string,password:string) {
|
export function check(id:string,password:string) {
|
||||||
let acc = Accounts.find(e => e.id == id)
|
let acc = Accounts.find(e => e.id == id)
|
||||||
if (!acc) return
|
if (!acc) return
|
||||||
|
@ -93,6 +139,12 @@ export namespace password {
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace files {
|
export namespace files {
|
||||||
|
/**
|
||||||
|
* @description Adds a file to an account's file index
|
||||||
|
* @param accountId The target account's ID
|
||||||
|
* @param fileId The target file's ID
|
||||||
|
* @returns Promise that resolves after accounts.json finishes writing
|
||||||
|
*/
|
||||||
export function index(accountId:string,fileId:string) {
|
export function index(accountId:string,fileId:string) {
|
||||||
// maybe replace with a obj like
|
// maybe replace with a obj like
|
||||||
// { x:true }
|
// { x:true }
|
||||||
|
@ -105,6 +157,13 @@ export namespace files {
|
||||||
return save()
|
return save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Removes a file from an account's file index
|
||||||
|
* @param accountId The target account's ID
|
||||||
|
* @param fileId The target file's ID
|
||||||
|
* @param noWrite Whether or not accounts.json should save
|
||||||
|
* @returns A Promise which resolves when accounts.json finishes writing, if `noWrite` is `false`
|
||||||
|
*/
|
||||||
export function deindex(accountId:string,fileId:string, noWrite:boolean=false) {
|
export function deindex(accountId:string,fileId:string, noWrite:boolean=false) {
|
||||||
let acc = Accounts.find(e => e.id == accountId)
|
let acc = Accounts.find(e => e.id == accountId)
|
||||||
if (!acc) return
|
if (!acc) return
|
||||||
|
@ -116,6 +175,10 @@ export namespace files {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Saves accounts.json
|
||||||
|
* @returns A promise which resolves when accounts.json finishes writing
|
||||||
|
*/
|
||||||
export function save() {
|
export function save() {
|
||||||
return writeFile(`${process.cwd()}/.data/accounts.json`,JSON.stringify(Accounts))
|
return writeFile(`${process.cwd()}/.data/accounts.json`,JSON.stringify(Accounts))
|
||||||
.catch((err) => console.error(err))
|
.catch((err) => console.error(err))
|
||||||
|
|
|
@ -3,6 +3,12 @@ import { readFile } from "fs/promises"
|
||||||
|
|
||||||
let errorPage:string
|
let errorPage:string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Serves an error as a response to a request with an error page attached
|
||||||
|
* @param res Express response object
|
||||||
|
* @param code Error code
|
||||||
|
* @param reason Error reason
|
||||||
|
*/
|
||||||
export default async function ServeError(
|
export default async function ServeError(
|
||||||
res:Response,
|
res:Response,
|
||||||
code:number,
|
code:number,
|
||||||
|
@ -29,7 +35,12 @@ export default async function ServeError(
|
||||||
.replace(/\$text/g,reason)
|
.replace(/\$text/g,reason)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @description Redirects a user to another page.
|
||||||
|
* @param res Express response object
|
||||||
|
* @param url Target URL
|
||||||
|
* @deprecated Use `res.redirect` instead.
|
||||||
|
*/
|
||||||
export function Redirect(res:Response,url:string) {
|
export function Redirect(res:Response,url:string) {
|
||||||
res.status(302)
|
res.status(302)
|
||||||
res.header("Location",url)
|
res.header("Location",url)
|
||||||
|
|
|
@ -14,6 +14,11 @@ export let alphanum = Array.from("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST
|
||||||
|
|
||||||
export type FileVisibility = "public" | "anonymous" | "private"
|
export type FileVisibility = "public" | "anonymous" | "private"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Generates an alphanumeric string, used for files
|
||||||
|
* @param length Length of the ID
|
||||||
|
* @returns a random alphanumeric string
|
||||||
|
*/
|
||||||
export function generateFileId(length:number=5) {
|
export function generateFileId(length:number=5) {
|
||||||
let fid = ""
|
let fid = ""
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
|
@ -40,7 +45,10 @@ export interface Configuration {
|
||||||
accounts: {
|
accounts: {
|
||||||
registrationEnabled: boolean,
|
registrationEnabled: boolean,
|
||||||
requiredForUpload: boolean
|
requiredForUpload: boolean
|
||||||
}
|
},
|
||||||
|
|
||||||
|
trustProxy: boolean,
|
||||||
|
forceSSL: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilePointer {
|
export interface FilePointer {
|
||||||
|
@ -93,6 +101,12 @@ export default class Files {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Uploads a new file
|
||||||
|
* @param settings Settings for your new upload
|
||||||
|
* @param fBuffer Buffer containing file content
|
||||||
|
* @returns Promise which resolves to the ID of the new file
|
||||||
|
*/
|
||||||
uploadFile(settings:FileUploadSettings,fBuffer:Buffer):Promise<string|StatusCodeError> {
|
uploadFile(settings:FileUploadSettings,fBuffer:Buffer):Promise<string|StatusCodeError> {
|
||||||
return new Promise<string>(async (resolve,reject) => {
|
return new Promise<string>(async (resolve,reject) => {
|
||||||
if (!this.uploadChannel) {
|
if (!this.uploadChannel) {
|
||||||
|
@ -244,6 +258,12 @@ export default class Files {
|
||||||
|
|
||||||
// fs
|
// fs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Writes a file to disk
|
||||||
|
* @param uploadId New file's ID
|
||||||
|
* @param file FilePointer representing the new file
|
||||||
|
* @returns Promise which resolves to the file's ID
|
||||||
|
*/
|
||||||
writeFile(uploadId: string, file: FilePointer):Promise<string> {
|
writeFile(uploadId: string, file: FilePointer):Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
@ -264,8 +284,12 @@ export default class Files {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: move read code here
|
/**
|
||||||
|
* @description Read a file
|
||||||
|
* @param uploadId Target file's ID
|
||||||
|
* @param range Byte range to get
|
||||||
|
* @returns A `Readable` containing the file's contents
|
||||||
|
*/
|
||||||
readFileStream(uploadId: string, range?: {start:number, end:number}):Promise<Readable> {
|
readFileStream(uploadId: string, range?: {start:number, end:number}):Promise<Readable> {
|
||||||
return new Promise(async (resolve,reject) => {
|
return new Promise(async (resolve,reject) => {
|
||||||
if (!this.uploadChannel) {
|
if (!this.uploadChannel) {
|
||||||
|
@ -401,6 +425,11 @@ export default class Files {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Deletes a file
|
||||||
|
* @param uploadId Target file's ID
|
||||||
|
* @param noWrite Whether or not the change should be written to disk. Enable for bulk deletes
|
||||||
|
*/
|
||||||
unlink(uploadId:string, noWrite: boolean = false):Promise<void> {
|
unlink(uploadId:string, noWrite: boolean = false):Promise<void> {
|
||||||
return new Promise(async (resolve,reject) => {
|
return new Promise(async (resolve,reject) => {
|
||||||
let tmp = this.files[uploadId];
|
let tmp = this.files[uploadId];
|
||||||
|
@ -431,6 +460,11 @@ export default class Files {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Get a file's FilePointer
|
||||||
|
* @param uploadId Target file's ID
|
||||||
|
* @returns FilePointer for the file
|
||||||
|
*/
|
||||||
getFilePointer(uploadId:string):FilePointer {
|
getFilePointer(uploadId:string):FilePointer {
|
||||||
return this.files[uploadId]
|
return this.files[uploadId]
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,13 @@ transport =
|
||||||
|
|
||||||
// lazy but
|
// lazy but
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Sends an email
|
||||||
|
* @param to Target email address
|
||||||
|
* @param subject Email subject
|
||||||
|
* @param content Email content
|
||||||
|
* @returns Promise which resolves to the output from nodemailer.transport.sendMail
|
||||||
|
*/
|
||||||
export function sendMail(to: string, subject: string, content: string) {
|
export function sendMail(to: string, subject: string, content: string) {
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
transport.sendMail({
|
transport.sendMail({
|
||||||
|
|
|
@ -3,11 +3,17 @@ import express, { type RequestHandler } from "express"
|
||||||
import ServeError from "../lib/errors";
|
import ServeError from "../lib/errors";
|
||||||
import * as auth from "./auth";
|
import * as auth from "./auth";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Middleware which adds an account, if any, to res.locals.acc
|
||||||
|
*/
|
||||||
export const getAccount: RequestHandler = function(req, res, next) {
|
export const getAccount: RequestHandler = function(req, res, next) {
|
||||||
res.locals.acc = Accounts.getFromToken(auth.tokenFor(req))
|
res.locals.acc = Accounts.getFromToken(auth.tokenFor(req))
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Middleware which blocks requests which do not have res.locals.acc set
|
||||||
|
*/
|
||||||
export const requiresAccount: RequestHandler = function(_req, res, next) {
|
export const requiresAccount: RequestHandler = function(_req, res, next) {
|
||||||
if (!res.locals.acc) {
|
if (!res.locals.acc) {
|
||||||
ServeError(res, 401, "not logged in")
|
ServeError(res, 401, "not logged in")
|
||||||
|
@ -16,6 +22,9 @@ export const requiresAccount: RequestHandler = function(_req, res, next) {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Middleware which blocks requests that have res.locals.acc.admin set to a falsy value
|
||||||
|
*/
|
||||||
export const requiresAdmin: RequestHandler = function(_req, res, next) {
|
export const requiresAdmin: RequestHandler = function(_req, res, next) {
|
||||||
if (!res.locals.acc.admin) {
|
if (!res.locals.acc.admin) {
|
||||||
ServeError(res, 403, "you are not an administrator")
|
ServeError(res, 403, "you are not an administrator")
|
||||||
|
@ -25,10 +34,10 @@ export const requiresAdmin: RequestHandler = function(_req, res, next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Blocks requests based on the permissions which a token has. Does not apply to routes being accessed with a token of type `User`
|
* @description Blocks requests based on the permissions which a token has. Does not apply to routes being accessed with a token of type `User`
|
||||||
* @param tokenPermissions Permissions which your route requires.
|
* @param tokenPermissions Permissions which your route requires.
|
||||||
* @returns Express middleware
|
* @returns Express middleware
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const requiresPermissions = function(...tokenPermissions: auth.TokenPermission[]): RequestHandler {
|
export const requiresPermissions = function(...tokenPermissions: auth.TokenPermission[]): RequestHandler {
|
||||||
return function(req, res, next) {
|
return function(req, res, next) {
|
||||||
|
|
|
@ -2,14 +2,19 @@ import { RequestHandler } from "express"
|
||||||
import { type Account } from "./accounts"
|
import { type Account } from "./accounts"
|
||||||
import ServeError from "./errors"
|
import ServeError from "./errors"
|
||||||
|
|
||||||
interface ratelimitSettings {
|
interface RatelimitSettings {
|
||||||
|
|
||||||
requests: number
|
requests: number
|
||||||
per: number
|
per: number
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function accountRatelimit( settings: ratelimitSettings ): RequestHandler {
|
/**
|
||||||
|
* @description Ratelimits a route based on res.locals.acc
|
||||||
|
* @param settings Ratelimit settings
|
||||||
|
* @returns Express middleware
|
||||||
|
*/
|
||||||
|
export function accountRatelimit( settings: RatelimitSettings ): RequestHandler {
|
||||||
let activeLimits: {
|
let activeLimits: {
|
||||||
[ key: string ]: {
|
[ key: string ]: {
|
||||||
requests: number,
|
requests: number,
|
||||||
|
|
Loading…
Reference in a new issue