Skip to content
This repository has been archived by the owner on Apr 23, 2024. It is now read-only.

Commit

Permalink
Merge pull request #354 from mgilangjanuar/staging
Browse files Browse the repository at this point in the history
Release v2.3.4
  • Loading branch information
mgilangjanuar authored May 13, 2022
2 parents d1b4446 + e246465 commit 9554238
Show file tree
Hide file tree
Showing 33 changed files with 1,434 additions and 1,943 deletions.
5 changes: 2 additions & 3 deletions api/.env-example
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ ADMIN_USERNAME=

DATABASE_URL=postgresql://postgres@localhost:5432/teledrive

API_JWT_SECRET=WDpojmXTH4ZPl3N2khUPPcAezLLpc8Mm
FILES_JWT_SECRET=nWHVW3arIdjC8Vy3g9rU2N6sKWmfPp7Z

IS_MAINTENANCE=

CACHE_FILES_LIMIT=20GB
6 changes: 4 additions & 2 deletions api/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "api",
"version": "2.3.3",
"version": "2.3.4",
"main": "dist/index.js",
"license": "MIT",
"private": true,
"scripts": {
"start": "nodemon dist/index.js --watch",
"prebuild": "prisma generate",
"build": "rimraf dist && eslint -c .eslintrc.js --ext .ts . && tsc"
"build": "rimraf dist && eslint -c .eslintrc.js --ext .ts . && tsc",
"postbuild": "test -f keys || (node -e \"console.log(require('crypto').randomBytes(48).toString('base64'));\" > keys && node -e \"console.log(require('crypto').randomBytes(48).toString('base64'));\" >> keys)"
},
"dependencies": {
"@prisma/client": "^3.14.0",
Expand All @@ -29,6 +30,7 @@
"express-rate-limit": "^5.3.0",
"flatted": "^3.2.2",
"geoip-lite": "^1.4.2",
"human-format": "^1.0.0",
"input": "^1.0.1",
"ioredis": "^4.28.2",
"is-uuid": "^1.0.2",
Expand Down
12 changes: 6 additions & 6 deletions api/src/api/middlewares/Auth.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { NextFunction, Request, Response } from 'express'
import { verify } from 'jsonwebtoken'
import { Logger, TelegramClient } from 'teledrive-client'
import { LogLevel } from 'teledrive-client/extensions/Logger'
import { StringSession } from 'teledrive-client/sessions'
import { NextFunction, Request, Response } from 'express'
import { verify } from 'jsonwebtoken'
import { Redis } from '../../service/Cache'
import { CONNECTION_RETRIES, TG_CREDS } from '../../utils/Constant'
import { prisma } from '../../model'
import { Redis } from '../../service/Cache'
import { API_JWT_SECRET, CONNECTION_RETRIES, TG_CREDS } from '../../utils/Constant'

export async function Auth(req: Request, _: Response, next: NextFunction): Promise<any> {
const authkey = (req.headers.authorization || req.cookies.authorization)?.replace(/^Bearer\ /gi, '')
Expand All @@ -15,7 +15,7 @@ export async function Auth(req: Request, _: Response, next: NextFunction): Promi

let data: { session: string }
try {
data = verify(authkey, process.env.API_JWT_SECRET) as { session: string }
data = verify(authkey, API_JWT_SECRET) as { session: string }
} catch (error) {
throw { status: 401, body: { error: 'Access token is invalid' } }
}
Expand Down Expand Up @@ -67,7 +67,7 @@ export async function AuthMaybe(req: Request, _: Response, next: NextFunction):
if (authkey) {
let data: { session: string }
try {
data = verify(authkey, process.env.API_JWT_SECRET) as { session: string }
data = verify(authkey, API_JWT_SECRET) as { session: string }
} catch (error) {
// throw { status: 401, body: { error: 'Access token is invalid' } }
return next()
Expand Down
8 changes: 4 additions & 4 deletions api/src/api/middlewares/TGSessionAuth.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { NextFunction, Request, Response } from 'express'
import { verify } from 'jsonwebtoken'
import { Logger, TelegramClient } from 'teledrive-client'
import { LogLevel } from 'teledrive-client/extensions/Logger'
import { StringSession } from 'teledrive-client/sessions'
import { NextFunction, Request, Response } from 'express'
import { verify } from 'jsonwebtoken'
import { CONNECTION_RETRIES, TG_CREDS } from '../../utils/Constant'
import { API_JWT_SECRET, CONNECTION_RETRIES, TG_CREDS } from '../../utils/Constant'

export async function TGSessionAuth(req: Request, _: Response, next: NextFunction): Promise<any> {
const authkey = (req.headers.authorization || req.cookies.authorization)?.replace(/^Bearer\ /gi, '')
Expand All @@ -13,7 +13,7 @@ export async function TGSessionAuth(req: Request, _: Response, next: NextFunctio

let data: { session: string }
try {
data = verify(authkey, process.env.API_JWT_SECRET) as { session: string }
data = verify(authkey, API_JWT_SECRET) as { session: string }
} catch (error) {
throw { status: 401, body: { error: 'Access token is invalid' } }
}
Expand Down
34 changes: 17 additions & 17 deletions api/src/api/v1/Auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { computeCheck } from 'teledrive-client/Password'
import { StringSession } from 'teledrive-client/sessions'
import { prisma } from '../../model'
import { Redis } from '../../service/Cache'
import { CONNECTION_RETRIES, COOKIE_AGE, TG_CREDS } from '../../utils/Constant'
import { API_JWT_SECRET, CONNECTION_RETRIES, COOKIE_AGE, FILES_JWT_SECRET, TG_CREDS } from '../../utils/Constant'
import { Endpoint } from '../base/Endpoint'
import { TGClient } from '../middlewares/TGClient'
import { TGSessionAuth } from '../middlewares/TGSessionAuth'
Expand All @@ -35,7 +35,7 @@ export class Auth {
})
}))
const session = req.tg.session.save()
const accessToken = sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '3h' })
const accessToken = sign({ session }, API_JWT_SECRET, { expiresIn: '3h' })
return res.cookie('authorization', `Bearer ${accessToken}`)
.send({ phoneCodeHash, timeout, accessToken })
}
Expand All @@ -51,7 +51,7 @@ export class Auth {
const { phoneCodeHash: newPhoneCodeHash, timeout } = await req.tg.invoke(new Api.auth.ResendCode({
phoneNumber, phoneCodeHash }))
const session = req.tg.session.save()
const accessToken = sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '3h' })
const accessToken = sign({ session }, API_JWT_SECRET, { expiresIn: '3h' })
return res.cookie('authorization', `Bearer ${accessToken}`)
.send({ phoneCodeHash: newPhoneCodeHash, timeout, accessToken })
}
Expand Down Expand Up @@ -112,8 +112,8 @@ export class Auth {
const session = req.tg.session.save()
const auth = {
session,
accessToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '1y' }),
accessToken: sign({ session }, API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, API_JWT_SECRET, { expiresIn: '1y' }),
expiredAfter: Date.now() + COOKIE_AGE
}

Expand All @@ -133,7 +133,7 @@ export class Auth {
]
}
}).then(files => files?.map(file => {
const signedKey = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), process.env.FILES_JWT_SECRET).toString()
const signedKey = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), FILES_JWT_SECRET).toString()
prisma.files.update({
data: { signed_key: signedKey },
where: { id: file.id }
Expand All @@ -150,7 +150,7 @@ export class Auth {

let data: { session: string }
try {
data = verify(refreshToken, process.env.API_JWT_SECRET) as { session: string }
data = verify(refreshToken, API_JWT_SECRET) as { session: string }
} catch (error) {
throw { status: 400, body: { error: 'Refresh token is invalid' } }
}
Expand Down Expand Up @@ -184,8 +184,8 @@ export class Auth {
const session = req.tg.session.save()
const auth = {
session,
accessToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '100y' }),
accessToken: sign({ session }, API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, API_JWT_SECRET, { expiresIn: '100y' }),
expiredAfter: Date.now() + COOKIE_AGE
}
return res
Expand Down Expand Up @@ -214,8 +214,8 @@ export class Auth {
const session = req.tg.session.save()
const auth = {
session,
accessToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '100y' }),
accessToken: sign({ session }, API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, API_JWT_SECRET, { expiresIn: '100y' }),
expiredAfter: Date.now() + COOKIE_AGE
}
return res
Expand Down Expand Up @@ -288,8 +288,8 @@ export class Auth {
const session = req.tg.session.save()
const auth = {
session,
accessToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '1y' }),
accessToken: sign({ session }, API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, API_JWT_SECRET, { expiresIn: '1y' }),
expiredAfter: Date.now() + COOKIE_AGE
}

Expand All @@ -309,7 +309,7 @@ export class Auth {
]
}
}).then(files => files?.map(file => {
const signedKey = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), process.env.FILES_JWT_SECRET).toString()
const signedKey = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), FILES_JWT_SECRET).toString()
prisma.files.update({
data: { signed_key: signedKey },
where: { id: file.id }
Expand All @@ -331,8 +331,8 @@ export class Auth {
const session = req.tg.session.save()
const auth = {
session,
accessToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, process.env.API_JWT_SECRET, { expiresIn: '1y' }),
accessToken: sign({ session }, API_JWT_SECRET, { expiresIn: '15h' }),
refreshToken: sign({ session }, API_JWT_SECRET, { expiresIn: '1y' }),
expiredAfter: Date.now() + COOKIE_AGE
}
res
Expand All @@ -352,7 +352,7 @@ export class Auth {
]
}
}).then(files => files?.map(file => {
const signedKey = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), process.env.FILES_JWT_SECRET).toString()
const signedKey = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), FILES_JWT_SECRET).toString()
prisma.files.update({
data: { signed_key: signedKey },
where: { id: file.id }
Expand Down
62 changes: 23 additions & 39 deletions api/src/api/v1/Files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import bigInt from 'big-integer'
import contentDisposition from 'content-disposition'
import { AES, enc } from 'crypto-js'
import { Request, Response } from 'express'
import { appendFileSync, createReadStream, existsSync, mkdirSync, renameSync, rmSync, statSync, writeFileSync } from 'fs'
import { appendFileSync, createReadStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from 'fs'
import moment from 'moment'
import multer from 'multer'
import { Api, Logger, TelegramClient } from 'teledrive-client'
import { LogLevel } from 'teledrive-client/extensions/Logger'
import { StringSession } from 'teledrive-client/sessions'
import { prisma } from '../../model'
import { Redis } from '../../service/Cache'
import { CONNECTION_RETRIES, TG_CREDS } from '../../utils/Constant'
import { CACHE_FILES_LIMIT, CONNECTION_RETRIES, FILES_JWT_SECRET, TG_CREDS } from '../../utils/Constant'
import { buildSort } from '../../utils/FilterQuery'
import { Endpoint } from '../base/Endpoint'
import { Auth, AuthMaybe } from '../middlewares/Auth'
Expand Down Expand Up @@ -385,7 +385,7 @@ export class Files {

let key: string = currentFile.signed_key || parent?.signed_key
if (file.sharing_options?.length && !key) {
key = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), process.env.FILES_JWT_SECRET).toString()
key = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), FILES_JWT_SECRET).toString()
}

if (!file.sharing_options?.length && !currentFile.sharing_options?.length && !parent?.sharing_options?.length) {
Expand Down Expand Up @@ -973,21 +973,6 @@ export class Files {

let cancel = false
req.on('close', () => cancel = true)
// res.setHeader('Cache-Control', 'public, max-age=604800')
// res.setHeader('ETag', Buffer.from(`${files[0].id}:${files[0].message_id}`).toString('base64'))
// res.setHeader('Content-Range', `bytes */${totalFileSize}`)
// res.setHeader('Content-Disposition', contentDisposition(files[0].name.replace(/\.part\d+$/gi, ''), { type: Number(dl) === 1 ? 'attachment' : 'inline' }))
// res.setHeader('Content-Type', files[0].mime_type)
// res.setHeader('Content-Length', totalFileSize.toString())
// res.setHeader('Accept-Ranges', 'bytes')

// res.writeHead(206, {
// 'Content-Disposition': contentDisposition(files[0].name.replace(/\.part\d+$/gi, ''), { type: Number(dl) === 1 ? 'attachment' : 'inline' }),
// 'Content-Type': files[0].mime_type,
// 'Content-Length': totalFileSize.toString(),
// 'Accept-Ranges': 'bytes',
// // 'Content-Range': `bytes ${downloaded - buffer.length}-${downloaded}/${buffer.length}`
// })

const ranges = req.headers.range ? req.headers.range.replace(/bytes\=/gi, '').split('-').map(Number) : null

Expand All @@ -1000,6 +985,15 @@ export class Files {
// ignore
}

const cachedFiles = () => readdirSync(`${__dirname}/../../../../.cached`)
.filter(filename =>
statSync(`${__dirname}/../../../../.cached/${filename}`).isFile()
).sort((a, b) =>
new Date(statSync(`${__dirname}/../../../../.cached/${a}`).birthtime).getTime()
- new Date(statSync(`${__dirname}/../../../../.cached/${b}`).birthtime).getTime()
)
const getCachedFilesSize = () => cachedFiles().reduce((res, file) => res + statSync(`${__dirname}/../../../../.cached/${file}`).size, 0)

if (existsSync(filename())) {
if (ranges) {
const start = ranges[0]
Expand Down Expand Up @@ -1034,8 +1028,8 @@ export class Files {
return
}

res.setHeader('Cache-Control', 'public, max-age=604800')
res.setHeader('ETag', Buffer.from(`${files[0].id}:${files[0].message_id}`).toString('base64'))
// res.setHeader('Cache-Control', 'public, max-age=604800')
// res.setHeader('ETag', Buffer.from(`${files[0].id}:${files[0].message_id}`).toString('base64'))
res.setHeader('Content-Range', `bytes */${totalFileSize}`)
res.setHeader('Content-Disposition', contentDisposition(files[0].name.replace(/\.part\d+$/gi, ''), { type: Number(dl) === 1 ? 'attachment' : 'inline' }))
res.setHeader('Content-Type', files[0].mime_type)
Expand Down Expand Up @@ -1109,24 +1103,6 @@ export class Files {
} catch (error) {
console.log(error)
}

// let trial = 0
// while (trial < PROCESS_RETRY) {
// try {
// await getData()
// trial = PROCESS_RETRY
// } catch (error) {
// console.log(error)
// if (error.status !== 422) {
// if (trial >= PROCESS_RETRY) {
// throw error
// }
// await new Promise(resolve => setTimeout(resolve, ++trial * 3000))
// await req.tg?.connect()
// }
// }
// }

}
usage = await prisma.usages.update({
data: {
Expand All @@ -1135,6 +1111,14 @@ export class Files {
where: { key: usage.key }
})

while (CACHE_FILES_LIMIT < getCachedFilesSize()) {
try {
rmSync(`${__dirname}/../../../../.cached/${cachedFiles()[0]}`)
} catch {
// ignore
}
}

// res.end()
}

Expand All @@ -1145,7 +1129,7 @@ export class Files {

let data: { file: { id: string }, session: string }
try {
data = JSON.parse(AES.decrypt(files[0].signed_key, process.env.FILES_JWT_SECRET).toString(enc.Utf8))
data = JSON.parse(AES.decrypt(files[0].signed_key, FILES_JWT_SECRET).toString(enc.Utf8))
} catch (error) {
throw { status: 401, body: { error: 'Invalid token' } }
}
Expand Down
51 changes: 0 additions & 51 deletions api/src/service/Midtrans.ts

This file was deleted.

Loading

1 comment on commit 9554238

@vercel
Copy link

@vercel vercel bot commented on 9554238 May 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.