mirror of
https://github.com/mollersuite/monofile.git
synced 2024-11-22 05:46:26 -08:00
Merge pull request #77 from mollersuite/db-file-handler
DB file handler script thingy
This commit is contained in:
commit
37f88d6984
|
@ -4,30 +4,12 @@ import { readFile, writeFile } from "fs/promises"
|
||||||
import { FileVisibility } from "./files.js";
|
import { FileVisibility } from "./files.js";
|
||||||
import { AccountSchemas } from "./schemas/index.js";
|
import { AccountSchemas } from "./schemas/index.js";
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
import DbFile from "./dbfile.js";
|
||||||
|
|
||||||
// this is probably horrible
|
// this is probably horrible
|
||||||
// but i don't even care anymore
|
// but i don't even care anymore
|
||||||
|
|
||||||
export let Accounts: Account[] = []
|
export let Db = new DbFile<Account[]>("accounts",[])
|
||||||
/*
|
|
||||||
export interface Account {
|
|
||||||
id : string
|
|
||||||
username : string
|
|
||||||
email? : string
|
|
||||||
password : {
|
|
||||||
hash : string
|
|
||||||
salt : string
|
|
||||||
}
|
|
||||||
files : string[]
|
|
||||||
admin : boolean
|
|
||||||
defaultFileVisibility : FileVisibility
|
|
||||||
customCSS? : string
|
|
||||||
|
|
||||||
embed? : {
|
|
||||||
color? : string
|
|
||||||
largeImage? : boolean
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
export type Account = z.infer<typeof AccountSchemas.Account>
|
export type Account = z.infer<typeof AccountSchemas.Account>
|
||||||
|
|
||||||
|
@ -42,7 +24,7 @@ export type Account = z.infer<typeof AccountSchemas.Account>
|
||||||
export async function create(username:string,pwd:string,admin:boolean=false):Promise<string> {
|
export async function create(username:string,pwd:string,admin:boolean=false):Promise<string> {
|
||||||
let accId = crypto.randomBytes(12).toString("hex")
|
let accId = crypto.randomBytes(12).toString("hex")
|
||||||
|
|
||||||
Accounts.push(
|
Db.data.push(
|
||||||
{
|
{
|
||||||
id: accId,
|
id: accId,
|
||||||
username: username,
|
username: username,
|
||||||
|
@ -54,7 +36,7 @@ export async function create(username:string,pwd:string,admin:boolean=false):Pro
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
await save()
|
await Db.save()
|
||||||
return accId
|
return accId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +46,7 @@ export async function create(username:string,pwd:string,admin:boolean=false):Pro
|
||||||
* @returns An Account, if it exists
|
* @returns An Account, if it exists
|
||||||
*/
|
*/
|
||||||
export function getFromUsername(username:string) {
|
export function getFromUsername(username:string) {
|
||||||
return Accounts.find(e => e.username == username)
|
return Db.data.find(e => e.username == username)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +55,7 @@ export function getFromUsername(username:string) {
|
||||||
* @returns An Account, if it exists
|
* @returns An Account, if it exists
|
||||||
*/
|
*/
|
||||||
export function getFromId(id:string) {
|
export function getFromId(id:string) {
|
||||||
return Accounts.find(e => e.id == id)
|
return Db.data.find(e => e.id == id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,8 +74,8 @@ export function getFromToken(token:string) {
|
||||||
* @param id The target account's ID
|
* @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)
|
Db.data.splice(Db.data.findIndex(e => e.id == id),1)
|
||||||
return save()
|
return Db.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace password {
|
export namespace password {
|
||||||
|
@ -121,11 +103,11 @@ export namespace 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 = Db.data.find(e => e.id == id)
|
||||||
if (!acc) return
|
if (!acc) return
|
||||||
|
|
||||||
acc.password = hash(password)
|
acc.password = hash(password)
|
||||||
return save()
|
return Db.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -135,7 +117,7 @@ export namespace password {
|
||||||
* @param password Password to check
|
* @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 = Db.data.find(e => e.id == id)
|
||||||
if (!acc) return
|
if (!acc) return
|
||||||
|
|
||||||
return acc.password.hash == hash(password,acc.password.salt).hash
|
return acc.password.hash == hash(password,acc.password.salt).hash
|
||||||
|
@ -153,12 +135,12 @@ export namespace files {
|
||||||
// maybe replace with a obj like
|
// maybe replace with a obj like
|
||||||
// { x:true }
|
// { x:true }
|
||||||
// for faster lookups? not sure if it would be faster
|
// for faster lookups? not sure if it would be faster
|
||||||
let acc = Accounts.find(e => e.id == accountId)
|
let acc = Db.data.find(e => e.id == accountId)
|
||||||
if (!acc) return
|
if (!acc) return
|
||||||
if (acc.files.find(e => e == fileId)) return
|
if (acc.files.find(e => e == fileId)) return
|
||||||
|
|
||||||
acc.files.push(fileId)
|
acc.files.push(fileId)
|
||||||
if (!noWrite) return save()
|
if (!noWrite) return Db.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,31 +151,19 @@ export namespace files {
|
||||||
* @returns A Promise which resolves when accounts.json finishes writing, if `noWrite` is `false`
|
* @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 = Db.data.find(e => e.id == accountId)
|
||||||
if (!acc) return
|
if (!acc) return
|
||||||
let fi = acc.files.findIndex(e => e == fileId)
|
let fi = acc.files.findIndex(e => e == fileId)
|
||||||
if (fi >= 0) {
|
if (fi >= 0) {
|
||||||
acc.files.splice(fi,1)
|
acc.files.splice(fi,1)
|
||||||
if (!noWrite) return save()
|
if (!noWrite) return Db.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
Db.read()
|
||||||
* @description Saves accounts.json
|
.then(() => {
|
||||||
* @returns A promise which resolves when accounts.json finishes writing
|
if (!Db.data.find(e => e.admin)) {
|
||||||
*/
|
|
||||||
export function save() {
|
|
||||||
return writeFile(`${process.cwd()}/.data/accounts.json`,JSON.stringify(Accounts))
|
|
||||||
.catch((err) => console.error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
readFile(`${process.cwd()}/.data/accounts.json`)
|
|
||||||
.then((buf) => {
|
|
||||||
Accounts = JSON.parse(buf.toString())
|
|
||||||
}).catch(err => console.error(err))
|
|
||||||
.finally(() => {
|
|
||||||
if (!Accounts.find(e => e.admin)) {
|
|
||||||
create("admin","admin",true)
|
create("admin","admin",true)
|
||||||
}
|
}
|
||||||
})
|
})
|
|
@ -4,13 +4,15 @@ import type { Context } from "hono"
|
||||||
import { readFile, writeFile } from "fs/promises"
|
import { readFile, writeFile } from "fs/promises"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { AuthSchemas } from "./schemas/index.js"
|
import { AuthSchemas } from "./schemas/index.js"
|
||||||
export let AuthTokens: AuthToken[] = []
|
import DbFile from "./dbfile.js"
|
||||||
export let AuthTokenTO: { [key: string]: NodeJS.Timeout } = {}
|
export let AuthTokenTO: { [key: string]: NodeJS.Timeout } = {}
|
||||||
|
|
||||||
export type TokenPermission = z.infer<typeof AuthSchemas.Scope>
|
export type TokenPermission = z.infer<typeof AuthSchemas.Scope>
|
||||||
export type TokenType = z.infer<typeof AuthSchemas.TokenType>
|
export type TokenType = z.infer<typeof AuthSchemas.TokenType>
|
||||||
export type AuthToken = z.infer<typeof AuthSchemas.AuthToken>
|
export type AuthToken = z.infer<typeof AuthSchemas.AuthToken>
|
||||||
|
|
||||||
|
export const Db = new DbFile<AuthToken[]>("tokens", [])
|
||||||
|
|
||||||
export function create(
|
export function create(
|
||||||
id: string,
|
id: string,
|
||||||
expire: number | null = 24 * 60 * 60 * 1000,
|
expire: number | null = 24 * 60 * 60 * 1000,
|
||||||
|
@ -28,10 +30,10 @@ export function create(
|
||||||
type != "User" ? tokenPermissions || ["user"] : undefined,
|
type != "User" ? tokenPermissions || ["user"] : undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
AuthTokens.push(token)
|
Db.data.push(token)
|
||||||
tokenTimer(token)
|
tokenTimer(token)
|
||||||
|
|
||||||
save()
|
Db.save()
|
||||||
|
|
||||||
return token.token
|
return token.token
|
||||||
}
|
}
|
||||||
|
@ -46,7 +48,7 @@ export function tokenFor(ctx: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getToken(token: string) {
|
function getToken(token: string) {
|
||||||
return AuthTokens.find(
|
return Db.data.find(
|
||||||
(e) => e.token == token && (e.expire == null || Date.now() < e.expire)
|
(e) => e.token == token && (e.expire == null || Date.now() < e.expire)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -84,23 +86,14 @@ export function invalidate(token: string) {
|
||||||
clearTimeout(AuthTokenTO[token])
|
clearTimeout(AuthTokenTO[token])
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthTokens.splice(
|
Db.data.splice(
|
||||||
AuthTokens.findIndex((e) => e.token == token),
|
Db.data.findIndex((e) => e.token == token),
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
save()
|
Db.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function save() {
|
Db.read()
|
||||||
writeFile(
|
|
||||||
`${process.cwd()}/.data/tokens.json`,
|
|
||||||
JSON.stringify(AuthTokens)
|
|
||||||
).catch((err) => console.error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
readFile(`${process.cwd()}/.data/tokens.json`)
|
|
||||||
.then((buf) => {
|
.then((buf) => {
|
||||||
AuthTokens = JSON.parse(buf.toString())
|
Db.data.forEach((e) => tokenTimer(e))
|
||||||
AuthTokens.forEach((e) => tokenTimer(e))
|
|
||||||
})
|
})
|
||||||
.catch((err) => console.error(err))
|
|
||||||
|
|
156
src/server/lib/dbfile.ts
Normal file
156
src/server/lib/dbfile.ts
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
import { readFile, writeFile, rename, readdir } from "fs/promises"
|
||||||
|
import path from "node:path"
|
||||||
|
|
||||||
|
const DATADIR = `./.data`
|
||||||
|
const TICK = 500
|
||||||
|
|
||||||
|
export type Write = ReturnType<typeof writeFile>
|
||||||
|
|
||||||
|
// this is fucking stupid why did i write this
|
||||||
|
|
||||||
|
class Activity {
|
||||||
|
|
||||||
|
_write: () => Promise<any>
|
||||||
|
destroy: () => void
|
||||||
|
|
||||||
|
goal: number = Date.now()
|
||||||
|
lastWrite: number = Date.now()
|
||||||
|
clock? : { type: "precise", id: NodeJS.Timeout } | { type: "tick", id: NodeJS.Timeout, lastGoal: number }
|
||||||
|
|
||||||
|
constructor(writeFunc: () => Promise<any>, destroyFunc: () => void) {
|
||||||
|
this._write = writeFunc
|
||||||
|
this.destroy = destroyFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
write() {
|
||||||
|
this.lastWrite = Date.now();
|
||||||
|
return this._write()
|
||||||
|
}
|
||||||
|
|
||||||
|
finish() {
|
||||||
|
this.stopClock()
|
||||||
|
this.write()
|
||||||
|
this.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
if (!this.clock || !("lastGoal" in this.clock)) return
|
||||||
|
if (Date.now() > this.goal) return this.finish();
|
||||||
|
|
||||||
|
if (this.goal == this.clock.lastGoal)
|
||||||
|
this.startPreciseClock()
|
||||||
|
else
|
||||||
|
this.clock.lastGoal = this.goal
|
||||||
|
|
||||||
|
if (Date.now()-this.lastWrite > 15000)
|
||||||
|
this.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
stopClock() {
|
||||||
|
if (this.clock) clearTimeout(this.clock.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
startTickClock() {
|
||||||
|
this.stopClock()
|
||||||
|
this.clock = {
|
||||||
|
type: "tick",
|
||||||
|
id: setInterval(this.tick.bind(this), TICK),
|
||||||
|
lastGoal: this.goal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startPreciseClock() {
|
||||||
|
this.stopClock()
|
||||||
|
this.clock = {
|
||||||
|
type: "precise",
|
||||||
|
id: setTimeout(this.finish.bind(this), this.goal-Date.now())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set() {
|
||||||
|
this.goal = Date.now()+5000
|
||||||
|
if (!this.clock || this.clock.type != "tick")
|
||||||
|
this.startTickClock()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DbFile<Structure extends ({}|[])> {
|
||||||
|
|
||||||
|
name: string
|
||||||
|
data: Structure
|
||||||
|
activity?: Activity
|
||||||
|
|
||||||
|
private writeInProgress?: Promise<void>
|
||||||
|
private rewriteNeeded: boolean = false
|
||||||
|
private readonly files: string[]
|
||||||
|
|
||||||
|
constructor(name: string, defaultData: Structure) {
|
||||||
|
this.name = name
|
||||||
|
this.data = defaultData
|
||||||
|
this.files = [`${name}.json`, `${name}-b.json`].map(e => path.join(DATADIR, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
private async findAvailable() {
|
||||||
|
return (await readdir(DATADIR))
|
||||||
|
.filter(e => e.match(new RegExp(`^${this.name}(?:-b)?.json$`)))
|
||||||
|
.map(e => path.join(DATADIR, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Write files to disk; doesn't care about preventing corruption aside from the 2 copies
|
||||||
|
*/
|
||||||
|
private async write() {
|
||||||
|
|
||||||
|
let data = JSON.stringify(this.data)
|
||||||
|
for (let x of this.files)
|
||||||
|
await writeFile(x, data)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Write files to disk; checks if a write is in progress first
|
||||||
|
*/
|
||||||
|
private async queueWrite(): Promise<void> {
|
||||||
|
if (this.writeInProgress) { // if write in progress
|
||||||
|
this.rewriteNeeded = true // signify that a rewrite is needed
|
||||||
|
return this.writeInProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writeInProgress = this.write()
|
||||||
|
await this.writeInProgress; // wait for it to complete
|
||||||
|
delete this.writeInProgress; // then remove it
|
||||||
|
|
||||||
|
if (this.rewriteNeeded) return this.queueWrite() // queues up another write if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Starts saving data to disk
|
||||||
|
*/
|
||||||
|
async save() {
|
||||||
|
if (!this.activity)
|
||||||
|
this.activity =
|
||||||
|
new Activity(
|
||||||
|
this.queueWrite.bind(this),
|
||||||
|
() => delete this.activity
|
||||||
|
)
|
||||||
|
|
||||||
|
this.activity.set()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async tryRead(path: string) {
|
||||||
|
return JSON.parse((await readFile(path)).toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
async read() {
|
||||||
|
let availFiles = await this.findAvailable()
|
||||||
|
for (let x of availFiles) {
|
||||||
|
let data = await this.tryRead(x).catch(_ => null)
|
||||||
|
if (data !== null) {
|
||||||
|
this.data = data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ import * as Accounts from "./accounts.js"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import * as schemas from "./schemas/files.js"
|
import * as schemas from "./schemas/files.js"
|
||||||
import { issuesToMessage } from "./middleware.js"
|
import { issuesToMessage } from "./middleware.js"
|
||||||
import file from "../routes/api/v1/file/index.js"
|
import DbFile from "./dbfile.js"
|
||||||
|
|
||||||
export let alphanum = Array.from(
|
export let alphanum = Array.from(
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||||
|
@ -435,9 +435,9 @@ export class UploadStream extends Writable {
|
||||||
|
|
||||||
if (!this.uploadId) this.setUploadId(generateFileId())
|
if (!this.uploadId) this.setUploadId(generateFileId())
|
||||||
|
|
||||||
let ogf = this.files.files[this.uploadId!]
|
let ogf = this.files.db.data[this.uploadId!]
|
||||||
|
|
||||||
this.files.files[this.uploadId!] = {
|
this.files.db.data[this.uploadId!] = {
|
||||||
filename: this.name,
|
filename: this.name,
|
||||||
mime: this.mime,
|
mime: this.mime,
|
||||||
messageids: this.messages,
|
messageids: this.messages,
|
||||||
|
@ -459,7 +459,7 @@ export class UploadStream extends Writable {
|
||||||
|
|
||||||
delete this.files.locks[this.uploadId!]
|
delete this.files.locks[this.uploadId!]
|
||||||
if (ogf?.messageids) await this.files.api.deleteMessages(ogf.messageids)
|
if (ogf?.messageids) await this.files.api.deleteMessages(ogf.messageids)
|
||||||
await this.files.write()
|
await this.files.db.save()
|
||||||
if (this.owner) Accounts.files.index(this.owner, this.uploadId!)
|
if (this.owner) Accounts.files.index(this.owner, this.uploadId!)
|
||||||
return this.uploadId
|
return this.uploadId
|
||||||
}
|
}
|
||||||
|
@ -508,7 +508,7 @@ export class UploadStream extends Writable {
|
||||||
if (!check.success)
|
if (!check.success)
|
||||||
return this.destroy(new WebError(400, issuesToMessage(check.error.issues)))
|
return this.destroy(new WebError(400, issuesToMessage(check.error.issues)))
|
||||||
|
|
||||||
if (this.files.files[id] && this.files.files[id].owner != this.owner)
|
if (this.files.db.data[id] && this.files.db.data[id].owner != this.owner)
|
||||||
return this.destroy(new WebError(403, "you don't own this file"))
|
return this.destroy(new WebError(403, "you don't own this file"))
|
||||||
|
|
||||||
if (this.files.locks[id])
|
if (this.files.locks[id])
|
||||||
|
@ -587,50 +587,27 @@ export class UploadStream extends Writable {
|
||||||
export default class Files {
|
export default class Files {
|
||||||
config: Configuration
|
config: Configuration
|
||||||
api: API
|
api: API
|
||||||
files: { [key: string]: FilePointer } = {}
|
db = new DbFile<{ [key: string]: FilePointer }>("files", {})
|
||||||
data_directory: string = `${process.cwd()}/.data`
|
|
||||||
|
|
||||||
locks: Record<string, boolean> = {} // I'll, like, do something more proper later
|
locks: Record<string, boolean> = {} // I'll, like, do something more proper later
|
||||||
|
|
||||||
constructor(config: Configuration) {
|
constructor(config: Configuration) {
|
||||||
this.config = config
|
this.config = config
|
||||||
this.api = new API(config.discordToken!, config)
|
this.api = new API(config.discordToken!, config)
|
||||||
|
this.db.read()
|
||||||
readFile(this.data_directory + "/files.json")
|
|
||||||
.then((buf) => {
|
|
||||||
this.files = JSON.parse(buf.toString() || "{}")
|
|
||||||
})
|
|
||||||
.catch(console.error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createWriteStream(owner?: string) {
|
createWriteStream(owner?: string) {
|
||||||
return new UploadStream(this, owner)
|
return new UploadStream(this, owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fs
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description Saves file database
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
async write(): Promise<void> {
|
|
||||||
await writeFile(
|
|
||||||
this.data_directory + "/files.json",
|
|
||||||
JSON.stringify(
|
|
||||||
this.files,
|
|
||||||
null,
|
|
||||||
process.env.NODE_ENV === "development" ? 4 : undefined
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Update a file from monofile 1.x to 2.x
|
* @description Update a file from monofile 1.x to 2.x
|
||||||
* @param uploadId Target file's ID
|
* @param uploadId Target file's ID
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async update(uploadId: string) {
|
async update(uploadId: string) {
|
||||||
let target_file = this.files[uploadId]
|
let target_file = this.db.data[uploadId]
|
||||||
let attachments: APIAttachment[] = []
|
let attachments: APIAttachment[] = []
|
||||||
|
|
||||||
for (let message of target_file.messageids) {
|
for (let message of target_file.messageids) {
|
||||||
|
@ -668,8 +645,8 @@ export default class Files {
|
||||||
uploadId: string,
|
uploadId: string,
|
||||||
range?: { start: number; end: number }
|
range?: { start: number; end: number }
|
||||||
): Promise<ReadStream> {
|
): Promise<ReadStream> {
|
||||||
if (this.files[uploadId]) {
|
if (this.db.data[uploadId]) {
|
||||||
let file = this.files[uploadId]
|
let file = this.db.data[uploadId]
|
||||||
if (!file.sizeInBytes || !file.chunkSize)
|
if (!file.sizeInBytes || !file.chunkSize)
|
||||||
await this.update(uploadId)
|
await this.update(uploadId)
|
||||||
return new ReadStream(this, file, range)
|
return new ReadStream(this, file, range)
|
||||||
|
@ -684,7 +661,7 @@ export default class Files {
|
||||||
* @param noWrite Whether or not the change should be written to disk. Enable for bulk deletes
|
* @param noWrite Whether or not the change should be written to disk. Enable for bulk deletes
|
||||||
*/
|
*/
|
||||||
async unlink(uploadId: string, noWrite: boolean = false): Promise<void> {
|
async unlink(uploadId: string, noWrite: boolean = false): Promise<void> {
|
||||||
let target = this.files[uploadId]
|
let target = this.db.data[uploadId]
|
||||||
if (!target) return
|
if (!target) return
|
||||||
|
|
||||||
await this.api.deleteMessages(target.messageids)
|
await this.api.deleteMessages(target.messageids)
|
||||||
|
@ -693,14 +670,14 @@ export default class Files {
|
||||||
let id = files.deindex(target.owner, uploadId, noWrite)
|
let id = files.deindex(target.owner, uploadId, noWrite)
|
||||||
if (id) await id
|
if (id) await id
|
||||||
}
|
}
|
||||||
delete this.files[uploadId]
|
delete this.db.data[uploadId]
|
||||||
|
|
||||||
if (!noWrite)
|
if (!noWrite)
|
||||||
return this.write()
|
return this.db.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
async chown(uploadId: string, newOwner?: string, noWrite: boolean = false) {
|
async chown(uploadId: string, newOwner?: string, noWrite: boolean = false) {
|
||||||
let target = this.files[uploadId]
|
let target = this.db.data[uploadId]
|
||||||
if (target.owner) {
|
if (target.owner) {
|
||||||
let i = files.deindex(target.owner, uploadId, Boolean(newOwner && noWrite))
|
let i = files.deindex(target.owner, uploadId, Boolean(newOwner && noWrite))
|
||||||
if (i) await i
|
if (i) await i
|
||||||
|
@ -713,24 +690,24 @@ export default class Files {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!noWrite)
|
if (!noWrite)
|
||||||
return this.write()
|
return this.db.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
async mv(uploadId: string, newId: string, noWrite: boolean = false) {
|
async mv(uploadId: string, newId: string, noWrite: boolean = false) {
|
||||||
let target = this.files[uploadId]
|
let target = this.db.data[uploadId]
|
||||||
if (target.owner) {
|
if (target.owner) {
|
||||||
let owner = Accounts.getFromId(target.owner)
|
let owner = Accounts.getFromId(target.owner)
|
||||||
if (owner) {
|
if (owner) {
|
||||||
owner.files.splice(owner.files.indexOf(uploadId), 1, newId)
|
owner.files.splice(owner.files.indexOf(uploadId), 1, newId)
|
||||||
if (!noWrite)
|
if (!noWrite)
|
||||||
await Accounts.save()
|
await Accounts.Db.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.files[newId] = target
|
this.db.data[newId] = target
|
||||||
delete this.files[uploadId]
|
delete this.db.data[uploadId]
|
||||||
|
|
||||||
if (!noWrite)
|
if (!noWrite)
|
||||||
return this.write()
|
return this.db.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,7 +40,7 @@ export default function (files: Files) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Accounts.password.set(targetAccount.id, body.password)
|
Accounts.password.set(targetAccount.id, body.password)
|
||||||
auth.AuthTokens.filter((e) => e.account == targetAccount?.id).forEach(
|
auth.Db.data.filter((e) => e.account == targetAccount?.id).forEach(
|
||||||
(v) => {
|
(v) => {
|
||||||
auth.invalidate(v.token)
|
auth.invalidate(v.token)
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ export default function (files: Files) {
|
||||||
return ctx.text("not found", 404)
|
return ctx.text("not found", 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
Accounts.save()
|
Accounts.Db.save()
|
||||||
return ctx.text("OK")
|
return ctx.text("OK")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ export default function (files: Files) {
|
||||||
return ctx.text("not found", 404)
|
return ctx.text("not found", 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetFile = files.files[body.target]
|
let targetFile = files.db.data[body.target]
|
||||||
|
|
||||||
if (!targetFile) {
|
if (!targetFile) {
|
||||||
return ctx.text("not found", 404)
|
return ctx.text("not found", 404)
|
||||||
|
@ -106,7 +106,7 @@ export default function (files: Files) {
|
||||||
|
|
||||||
let accId = targetAccount.id
|
let accId = targetAccount.id
|
||||||
|
|
||||||
auth.AuthTokens.filter((e) => e.account == accId).forEach((v) => {
|
auth.Db.data.filter((e) => e.account == accId).forEach((v) => {
|
||||||
auth.invalidate(v.token)
|
auth.invalidate(v.token)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ export default function (files: Files) {
|
||||||
|
|
||||||
return writeFile(
|
return writeFile(
|
||||||
process.cwd() + "/.data/files.json",
|
process.cwd() + "/.data/files.json",
|
||||||
JSON.stringify(files.files)
|
JSON.stringify(files.db.data)
|
||||||
).then(cpl)
|
).then(cpl)
|
||||||
} else return cpl()
|
} else return cpl()
|
||||||
})
|
})
|
||||||
|
@ -151,7 +151,7 @@ export default function (files: Files) {
|
||||||
return ctx.text("not found", 404)
|
return ctx.text("not found", 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetFile = files.files[body.target]
|
let targetFile = files.db.data[body.target]
|
||||||
if (!targetFile) {
|
if (!targetFile) {
|
||||||
return ctx.text("not found", 404)
|
return ctx.text("not found", 404)
|
||||||
}
|
}
|
||||||
|
@ -172,8 +172,8 @@ export default function (files: Files) {
|
||||||
}
|
}
|
||||||
targetFile.owner = newOwner ? newOwner.id : undefined
|
targetFile.owner = newOwner ? newOwner.id : undefined
|
||||||
|
|
||||||
return files
|
return files.db
|
||||||
.write()
|
.save()
|
||||||
.then(() => ctx.text("ok", 200))
|
.then(() => ctx.text("ok", 200))
|
||||||
.catch(() => ctx.text("error", 500))
|
.catch(() => ctx.text("error", 500))
|
||||||
})
|
})
|
||||||
|
@ -184,12 +184,12 @@ export default function (files: Files) {
|
||||||
return ctx.text("inappropriate body", 400)
|
return ctx.text("inappropriate body", 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetFile = files.files[body.target]
|
let targetFile = files.db.data[body.target]
|
||||||
if (!targetFile) {
|
if (!targetFile) {
|
||||||
return ctx.text("not found", 404)
|
return ctx.text("not found", 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (files.files[body.new]) {
|
if (files.db.data[body.new]) {
|
||||||
return ctx.status(400)
|
return ctx.status(400)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,14 +197,14 @@ export default function (files: Files) {
|
||||||
Accounts.files.deindex(targetFile.owner, body.target)
|
Accounts.files.deindex(targetFile.owner, body.target)
|
||||||
Accounts.files.index(targetFile.owner, body.new)
|
Accounts.files.index(targetFile.owner, body.new)
|
||||||
}
|
}
|
||||||
delete files.files[body.target]
|
delete files.db.data[body.target]
|
||||||
files.files[body.new] = targetFile
|
files.db.data[body.new] = targetFile
|
||||||
|
|
||||||
return files
|
return files.db
|
||||||
.write()
|
.save()
|
||||||
.then(() => ctx.status(200))
|
.then(() => ctx.status(200))
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
files.files[body.target] = body.new
|
files.db.data[body.target] = body.new
|
||||||
|
|
||||||
if (targetFile.owner) {
|
if (targetFile.owner) {
|
||||||
Accounts.files.deindex(targetFile.owner, body.new)
|
Accounts.files.deindex(targetFile.owner, body.new)
|
||||||
|
|
|
@ -150,7 +150,7 @@ export default function (files: Files) {
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
acc.defaultFileVisibility = body.defaultFileVisibility
|
acc.defaultFileVisibility = body.defaultFileVisibility
|
||||||
Accounts.save()
|
Accounts.Db.save()
|
||||||
return ctx.text(
|
return ctx.text(
|
||||||
`dfv has been set to ${acc.defaultFileVisibility}`
|
`dfv has been set to ${acc.defaultFileVisibility}`
|
||||||
)
|
)
|
||||||
|
@ -170,7 +170,7 @@ export default function (files: Files) {
|
||||||
const body = await ctx.req.json()
|
const body = await ctx.req.json()
|
||||||
let accId = acc.id
|
let accId = acc.id
|
||||||
|
|
||||||
auth.AuthTokens.filter((e) => e.account == accId).forEach((v) => {
|
auth.Db.data.filter((e) => e.account == accId).forEach((v) => {
|
||||||
auth.invalidate(v.token)
|
auth.invalidate(v.token)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ export default function (files: Files) {
|
||||||
|
|
||||||
return writeFile(
|
return writeFile(
|
||||||
process.cwd() + "/.data/files.json",
|
process.cwd() + "/.data/files.json",
|
||||||
JSON.stringify(files.files)
|
JSON.stringify(files.db.data)
|
||||||
).then(cpl)
|
).then(cpl)
|
||||||
} else cpl()
|
} else cpl()
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ export default function (files: Files) {
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.username = body.username
|
acc.username = body.username
|
||||||
Accounts.save()
|
Accounts.Db.save()
|
||||||
|
|
||||||
if (acc.email) {
|
if (acc.email) {
|
||||||
return sendMail(
|
return sendMail(
|
||||||
|
@ -339,7 +339,7 @@ export default function (files: Files) {
|
||||||
ctx.req.param("code").toUpperCase() == vcode.code
|
ctx.req.param("code").toUpperCase() == vcode.code
|
||||||
) {
|
) {
|
||||||
acc.email = vcode.email
|
acc.email = vcode.email
|
||||||
Accounts.save()
|
Accounts.Db.save()
|
||||||
|
|
||||||
let e = verificationCodes.get(acc?.id || "")?.expiry
|
let e = verificationCodes.get(acc?.id || "")?.expiry
|
||||||
if (e) clearTimeout(e)
|
if (e) clearTimeout(e)
|
||||||
|
@ -361,7 +361,7 @@ export default function (files: Files) {
|
||||||
|
|
||||||
if (acc.email) {
|
if (acc.email) {
|
||||||
delete acc.email
|
delete acc.email
|
||||||
Accounts.save()
|
Accounts.Db.save()
|
||||||
return ctx.text("email detached")
|
return ctx.text("email detached")
|
||||||
} else return ServeError(ctx, 400, "email not attached")
|
} else return ServeError(ctx, 400, "email not attached")
|
||||||
}
|
}
|
||||||
|
@ -490,7 +490,7 @@ export default function (files: Files) {
|
||||||
|
|
||||||
Accounts.password.set(accId, body.password)
|
Accounts.password.set(accId, body.password)
|
||||||
|
|
||||||
auth.AuthTokens.filter((e) => e.account == accId).forEach((v) => {
|
auth.Db.data.filter((e) => e.account == accId).forEach((v) => {
|
||||||
auth.invalidate(v.token)
|
auth.invalidate(v.token)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ export default function (files: Files) {
|
||||||
|
|
||||||
let accId = acc.id
|
let accId = acc.id
|
||||||
|
|
||||||
auth.AuthTokens.filter((e) => e.account == accId).forEach((v) => {
|
auth.Db.data.filter((e) => e.account == accId).forEach((v) => {
|
||||||
auth.invalidate(v.token)
|
auth.invalidate(v.token)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -535,13 +535,13 @@ export default function (files: Files) {
|
||||||
let accId = acc.id
|
let accId = acc.id
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
...acc,
|
...acc,
|
||||||
sessionCount: auth.AuthTokens.filter(
|
sessionCount: auth.Db.data.filter(
|
||||||
(e) =>
|
(e) =>
|
||||||
e.type == "User" &&
|
e.type == "User" &&
|
||||||
e.account == accId &&
|
e.account == accId &&
|
||||||
(e.expire == null || e.expire > Date.now())
|
(e.expire == null || e.expire > Date.now())
|
||||||
).length,
|
).length,
|
||||||
sessionExpires: auth.AuthTokens.find(
|
sessionExpires: auth.Db.data.find(
|
||||||
(e) => e.token == sessionToken
|
(e) => e.token == sessionToken
|
||||||
)?.expire,
|
)?.expire,
|
||||||
password: undefined,
|
password: undefined,
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default function (files: Files) {
|
||||||
return ctx.json(
|
return ctx.json(
|
||||||
acc.files
|
acc.files
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
let fp = files.files[e]
|
let fp = files.db.data[e]
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
Accounts.files.deindex(accId, e)
|
Accounts.files.deindex(accId, e)
|
||||||
return null
|
return null
|
||||||
|
@ -66,7 +66,7 @@ export default function (files: Files) {
|
||||||
body.target.forEach((e: string) => {
|
body.target.forEach((e: string) => {
|
||||||
if (!acc.files.includes(e)) return
|
if (!acc.files.includes(e)) return
|
||||||
|
|
||||||
let fp = files.files[e]
|
let fp = files.db.data[e]
|
||||||
|
|
||||||
switch (body.action) {
|
switch (body.action) {
|
||||||
case "delete":
|
case "delete":
|
||||||
|
@ -81,15 +81,15 @@ export default function (files: Files) {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
files.files[e].visibility = body.value
|
files.db.data[e].visibility = body.value
|
||||||
modified++
|
modified++
|
||||||
break
|
break
|
||||||
|
|
||||||
case "setTag":
|
case "setTag":
|
||||||
if (!body.value) delete files.files[e].tag
|
if (!body.value) delete files.db.data[e].tag
|
||||||
else {
|
else {
|
||||||
if (body.value.toString().length > 30) return
|
if (body.value.toString().length > 30) return
|
||||||
files.files[e].tag = body.value
|
files.db.data[e].tag = body.value
|
||||||
.toString()
|
.toString()
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
}
|
}
|
||||||
|
@ -98,11 +98,11 @@ export default function (files: Files) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return Accounts.save()
|
return Accounts.Db.save()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
writeFile(
|
writeFile(
|
||||||
process.cwd() + "/.data/files.json",
|
process.cwd() + "/.data/files.json",
|
||||||
JSON.stringify(files.files)
|
JSON.stringify(files.db.data)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.then(() => ctx.text(`modified ${modified} files`))
|
.then(() => ctx.text(`modified ${modified} files`))
|
||||||
|
|
|
@ -38,7 +38,7 @@ type HonoEnv = {
|
||||||
const router = new Hono<HonoEnv>()
|
const router = new Hono<HonoEnv>()
|
||||||
|
|
||||||
function getTargetToken(ctx: Context<HonoEnv, "/:token", BlankInput>) {
|
function getTargetToken(ctx: Context<HonoEnv, "/:token", BlankInput>) {
|
||||||
return auth.AuthTokens.find(
|
return auth.Db.data.find(
|
||||||
e =>
|
e =>
|
||||||
e.account == ctx.get("target").id
|
e.account == ctx.get("target").id
|
||||||
&& e.token == ctx.req.param("token")
|
&& e.token == ctx.req.param("token")
|
||||||
|
@ -59,7 +59,7 @@ export default function (files: Files) {
|
||||||
|
|
||||||
router.get("/", async (ctx) => {
|
router.get("/", async (ctx) => {
|
||||||
return ctx.json(
|
return ctx.json(
|
||||||
auth.AuthTokens.filter(e => e.account == ctx.get("target").id)
|
auth.Db.data.filter(e => e.account == ctx.get("target").id)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ export default function (files: Files) {
|
||||||
(c) => c.req.query("type")?.split(",")
|
(c) => c.req.query("type")?.split(",")
|
||||||
),
|
),
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
let targets = auth.AuthTokens.filter(
|
let targets = auth.Db.data.filter(
|
||||||
e =>
|
e =>
|
||||||
e.account == ctx.get("target").id
|
e.account == ctx.get("target").id
|
||||||
&& ctx.get("parsedScheme").has(e.type)
|
&& ctx.get("parsedScheme").has(e.type)
|
||||||
|
|
|
@ -188,7 +188,7 @@ const validators: {
|
||||||
validator: (actor, target, params) => {
|
validator: (actor, target, params) => {
|
||||||
if (!actor.admin) return [400, "only admins can modify suspensions"]
|
if (!actor.admin) return [400, "only admins can modify suspensions"]
|
||||||
if (params.suspension)
|
if (params.suspension)
|
||||||
auth.AuthTokens
|
auth.Db.data
|
||||||
.filter(e => e.account == target.id)
|
.filter(e => e.account == target.id)
|
||||||
.forEach(e => auth.invalidate(e.token))
|
.forEach(e => auth.invalidate(e.token))
|
||||||
return params.suspension || undefined
|
return params.suspension || undefined
|
||||||
|
@ -320,7 +320,7 @@ export default function (files: Files) {
|
||||||
return [200, "OK"] as Message
|
return [200, "OK"] as Message
|
||||||
})
|
})
|
||||||
|
|
||||||
await Accounts.save()
|
await Accounts.Db.save()
|
||||||
|
|
||||||
if (messages.length == 1)
|
if (messages.length == 1)
|
||||||
return ctx.text(
|
return ctx.text(
|
||||||
|
@ -337,7 +337,7 @@ export default function (files: Files) {
|
||||||
if (actor == target && !verifyPoi(actor.id, ctx.req.query("poi")))
|
if (actor == target && !verifyPoi(actor.id, ctx.req.query("poi")))
|
||||||
return ServeError(ctx, 403, "invalid proof of identity provided")
|
return ServeError(ctx, 403, "invalid proof of identity provided")
|
||||||
|
|
||||||
auth.AuthTokens.filter((e) => e.account == target?.id).forEach((token) => {
|
auth.Db.data.filter((e) => e.account == target?.id).forEach((token) => {
|
||||||
auth.invalidate(token.token)
|
auth.invalidate(token.token)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ export default function (files: Files) {
|
||||||
auth.getPermissions(sessionToken)?.includes("email")
|
auth.getPermissions(sessionToken)?.includes("email")
|
||||||
? acc.email
|
? acc.email
|
||||||
: undefined,
|
: undefined,
|
||||||
activeSessions: auth.AuthTokens.filter(
|
activeSessions: auth.Db.data.filter(
|
||||||
(e) =>
|
(e) =>
|
||||||
e.type == "User" &&
|
e.type == "User" &&
|
||||||
e.account == acc.id &&
|
e.account == acc.id &&
|
||||||
|
|
|
@ -99,7 +99,7 @@ export default function(files: Files) {
|
||||||
|
|
||||||
parser.on("field", async (k,v) => {
|
parser.on("field", async (k,v) => {
|
||||||
if (k == "uploadId") {
|
if (k == "uploadId") {
|
||||||
if (files.files[v] && ctx.req.method == "POST")
|
if (files.db.data[v] && ctx.req.method == "POST")
|
||||||
return file.destroy(new WebError(409, "file already exists"))
|
return file.destroy(new WebError(409, "file already exists"))
|
||||||
file.setUploadId(v)
|
file.setUploadId(v)
|
||||||
// I'M GONNA KILL MYSELF!!!!
|
// I'M GONNA KILL MYSELF!!!!
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default function(files: Files, apiRoot: Hono) {
|
||||||
|
|
||||||
let acc = ctx.get("account") as Accounts.Account
|
let acc = ctx.get("account") as Accounts.Account
|
||||||
|
|
||||||
let file = files.files[fileId]
|
let file = files.db.data[fileId]
|
||||||
ctx.header("Accept-Ranges", "bytes")
|
ctx.header("Accept-Ranges", "bytes")
|
||||||
ctx.header("Access-Control-Allow-Origin", "*")
|
ctx.header("Access-Control-Allow-Origin", "*")
|
||||||
ctx.header("Content-Security-Policy", "sandbox allow-scripts")
|
ctx.header("Content-Security-Policy", "sandbox allow-scripts")
|
||||||
|
|
|
@ -17,8 +17,8 @@ export default function(files: Files) {
|
||||||
router.get("/", async (ctx) =>
|
router.get("/", async (ctx) =>
|
||||||
ctx.json({
|
ctx.json({
|
||||||
version: pkg.version,
|
version: pkg.version,
|
||||||
files: Object.keys(files.files).length,
|
files: Object.keys(files.db.data).length,
|
||||||
totalSize: Object.values(files.files).filter(e => e.sizeInBytes).reduce((acc,cur)=>acc+cur.sizeInBytes!,0),
|
totalSize: Object.values(files.db.data).filter(e => e.sizeInBytes).reduce((acc,cur)=>acc+cur.sizeInBytes!,0),
|
||||||
maxDiscordFiles: config.maxDiscordFiles,
|
maxDiscordFiles: config.maxDiscordFiles,
|
||||||
maxDiscordFileSize: config.maxDiscordFileSize,
|
maxDiscordFileSize: config.maxDiscordFileSize,
|
||||||
accounts: config.accounts,
|
accounts: config.accounts,
|
||||||
|
|
|
@ -61,7 +61,7 @@ export default function (files: Files) {
|
||||||
router.get("/", requiresAccount, ctx => {
|
router.get("/", requiresAccount, ctx => {
|
||||||
let sessionToken = auth.tokenFor(ctx)
|
let sessionToken = auth.tokenFor(ctx)
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
expiry: auth.AuthTokens.find(
|
expiry: auth.Db.data.find(
|
||||||
(e) => e.token == sessionToken
|
(e) => e.token == sessionToken
|
||||||
)?.expire,
|
)?.expire,
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default function (files: Files) {
|
||||||
}
|
}
|
||||||
|
|
||||||
currentAccount.email = code.data
|
currentAccount.email = code.data
|
||||||
await Accounts.save()
|
await Accounts.Db.save()
|
||||||
|
|
||||||
return ctx.redirect('/')
|
return ctx.redirect('/')
|
||||||
} else return ServeError(ctx, 404, "code not found")
|
} else return ServeError(ctx, 404, "code not found")
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default function (files: Files) {
|
||||||
let acc = ctx.get("account") as Accounts.Account
|
let acc = ctx.get("account") as Accounts.Account
|
||||||
const fileId = ctx.req.param("fileId")
|
const fileId = ctx.req.param("fileId")
|
||||||
const host = ctx.req.header("Host")
|
const host = ctx.req.header("Host")
|
||||||
const file = files.files[fileId]
|
const file = files.db.data[fileId]
|
||||||
if (file) {
|
if (file) {
|
||||||
if (file.visibility == "private" && acc?.id != file.owner) {
|
if (file.visibility == "private" && acc?.id != file.owner) {
|
||||||
return ServeError(ctx, 403, "you do not own this file")
|
return ServeError(ctx, 403, "you do not own this file")
|
||||||
|
|
|
@ -28,7 +28,7 @@ program
|
||||||
.alias("ls")
|
.alias("ls")
|
||||||
.description("List files in the database")
|
.description("List files in the database")
|
||||||
.action(() => {
|
.action(() => {
|
||||||
Object.keys(files.files).forEach((e) => console.log(e))
|
Object.keys(files.db.data).forEach((e) => console.log(e))
|
||||||
})
|
})
|
||||||
|
|
||||||
program
|
program
|
||||||
|
@ -40,7 +40,7 @@ program
|
||||||
.action(async (id, options) => {
|
.action(async (id, options) => {
|
||||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1000))
|
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1000))
|
||||||
|
|
||||||
let fp = files.files[id]
|
let fp = files.db.data[id]
|
||||||
|
|
||||||
if (!fp) throw `file ${id} not found`
|
if (!fp) throw `file ${id} not found`
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue