Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deno 2 experimental support #570

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"tasks": {
"dev": "deno run --watch main.ts"
},
"imports": {
"@std/assert": "jsr:@std/assert@1",
"@internal/": "./src/internal/",
"@storage/": "./src/storage/",
"postgres-migrations/": "npm:postgres-migrations/",
"postgres-migrations/dist/": "npm:postgres-migrations/dist/",
"ajv": "npm:ajv"
}
}
6 changes: 3 additions & 3 deletions src/http/error-handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FastifyInstance } from 'fastify'
import { FastifyError } from '@fastify/error'
import { DatabaseError } from 'pg'
import pg from 'pg'
import { ErrorCode, isRenderableError } from '@internal/errors'

/**
Expand All @@ -17,15 +17,15 @@

// database error
if (
error instanceof DatabaseError &&
error instanceof pg.DatabaseError &&
[
'Authentication error', // supavisor specific
'Max client connections reached',
'remaining connection slots are reserved for non-replication superuser connections',
'no more connections allowed',
'sorry, too many clients already',
'server login has been failing, try again later',
].some((msg) => (error as DatabaseError).message.includes(msg))
].some((msg) => (error as pg.DatabaseError).message.includes(msg))
) {
return reply.status(429).send({
statusCode: `429`,
Expand Down Expand Up @@ -64,7 +64,7 @@
// Fastify errors
if ('statusCode' in error) {
const err = error as FastifyError
return reply.status((error as any).statusCode || 500).send({

Check warning on line 67 in src/http/error-handler.ts

View workflow job for this annotation

GitHub Actions / Test / OS ubuntu-20.04 / Node 20

Unexpected any. Specify a different type
statusCode: `${err.statusCode}`,
error: err.name,
message: err.message,
Expand Down
3 changes: 1 addition & 2 deletions src/http/plugins/log-request.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import fastifyPlugin from 'fastify-plugin'
import { logSchema, redactQueryParamFromRequest } from '@internal/monitoring'
import { trace } from '@opentelemetry/api'
import { FastifyRequest } from 'fastify/types/request'
import { FastifyReply } from 'fastify/types/reply'
import { FastifyRequest, FastifyReply } from 'fastify'

interface RequestLoggerOptions {
excludeUrls?: string[]
Expand All @@ -18,7 +17,7 @@

interface FastifyContextConfig {
operation?: { type: string }
resources?: (req: FastifyRequest<any>) => string[]

Check warning on line 20 in src/http/plugins/log-request.ts

View workflow job for this annotation

GitHub Actions / Test / OS ubuntu-20.04 / Node 20

Unexpected any. Specify a different type
}
}

Expand Down Expand Up @@ -60,7 +59,7 @@
const resources = getFirstDefined<string[]>(
req.resources,
req.routeConfig.resources?.(req),
(req.raw as any).resources,

Check warning on line 62 in src/http/plugins/log-request.ts

View workflow job for this annotation

GitHub Actions / Test / OS ubuntu-20.04 / Node 20

Unexpected any. Specify a different type
resourceFromParams ? [resourceFromParams] : ([] as string[])
)

Expand Down Expand Up @@ -115,7 +114,7 @@
const rId = req.id
const cIP = req.ip
const statusCode = options.statusCode
const error = (req.raw as any).executionError || req.executionError

Check warning on line 117 in src/http/plugins/log-request.ts

View workflow job for this annotation

GitHub Actions / Test / OS ubuntu-20.04 / Node 20

Unexpected any. Specify a different type
const tenantId = req.tenantId

const buildLogMessage = `${tenantId} | ${rMeth} | ${statusCode} | ${cIP} | ${rId} | ${rUrl} | ${uAgent}`
Expand Down
2 changes: 1 addition & 1 deletion src/http/plugins/tracing.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import fastifyPlugin from 'fastify-plugin'
import { isIP } from 'net'
import { isIP } from 'node:net'
import { getTenantConfig } from '@internal/database'

import { getConfig } from '../../config'
Expand Down
2 changes: 1 addition & 1 deletion src/http/routes/object/getObject.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
import { FromSchema } from 'json-schema-to-ts'
import { IncomingMessage, Server, ServerResponse } from 'http'
import { IncomingMessage, Server, ServerResponse } from 'node:http'
import { getConfig } from '../../../config'
import { AuthenticatedRangeRequest } from '../../types'
import { ROUTE_OPERATIONS } from '../operations'
Expand Down
2 changes: 1 addition & 1 deletion src/http/routes/object/getObjectInfo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
import { FromSchema } from 'json-schema-to-ts'
import { IncomingMessage, Server, ServerResponse } from 'http'
import { IncomingMessage, Server, ServerResponse } from 'node:http'
import { getConfig } from '../../../config'
import { AuthenticatedRangeRequest } from '../../types'
import { Obj } from '@storage/schemas'
Expand Down
9 changes: 4 additions & 5 deletions src/http/routes/s3/error-handler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { FastifyError } from '@fastify/error'
import { FastifyRequest } from 'fastify/types/request'
import { FastifyReply } from 'fastify/types/reply'
import { FastifyReply, FastifyRequest } from 'fastify'
import { S3ServiceException } from '@aws-sdk/client-s3'
import { DatabaseError } from 'pg'
import pg from 'pg'
import { ErrorCode, StorageBackendError } from '@internal/errors'

export const s3ErrorHandler = (
Expand Down Expand Up @@ -41,14 +40,14 @@ export const s3ErrorHandler = (

// database error
if (
error instanceof DatabaseError &&
error instanceof pg.DatabaseError &&
[
'Max client connections reached',
'remaining connection slots are reserved for non-replication superuser connections',
'no more connections allowed',
'sorry, too many clients already',
'server login has been failing, try again later',
].some((msg) => (error as DatabaseError).message.includes(msg))
].some((msg) => (error as pg.DatabaseError).message.includes(msg))
) {
return reply.status(429).send({
Error: {
Expand Down
2 changes: 1 addition & 1 deletion src/http/routes/tus/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FastifyBaseLogger, FastifyInstance } from 'fastify'
import fastifyPlugin from 'fastify-plugin'
import * as http from 'http'
import * as http from 'node:http'
import { ServerOptions, DataStore } from '@tus/server'
import { getFileSizeLimit } from '@storage/limits'
import { Storage } from '@storage/storage'
Expand Down
4 changes: 2 additions & 2 deletions src/http/routes/tus/lifecycle.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import http from 'http'
import http from 'node:http'
import { BaseLogger } from 'pino'
import { Upload } from '@tus/server'
import { randomUUID } from 'crypto'
import { randomUUID } from 'node:crypto'
import { TenantConnection } from '@internal/database'
import { ERRORS, isRenderableError } from '@internal/errors'
import { Storage } from '@storage/storage'
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import './start/server'
import './start/server.ts'
54 changes: 43 additions & 11 deletions src/internal/auth/crypto.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,53 @@
import AES from 'crypto-js/aes'
import Utf8 from 'crypto-js/enc-utf8'
import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto'
import { getConfig } from '../../config'

const { encryptionKey } = getConfig()

/**
* Decrypts a text with the configured encryption key via ENCRYPTION_KEY env
* @param ciphertext
*/
* Generate CryptoJs.AES key from passphrase
* https://github.com/brix/crypto-js/issues/468
* */
function convertPassphraseToAesKeyBuffer(key: string, salt: Buffer): Buffer {
const password = Buffer.concat([Buffer.from(key, 'binary'), salt])
const hash: Buffer[] = []
let digest = password
for (let i = 0; i < 3; i++) {
hash[i] = createHash('md5').update(digest).digest()
digest = Buffer.concat([hash[i]!, password])
}
return Buffer.concat(hash)
}

/**
* Replicate CryptoJs.AES.decrypt method
* */
export function decrypt(ciphertext: string): string {
return AES.decrypt(ciphertext, encryptionKey).toString(Utf8)
try {
const cipherBuffer = Buffer.from(ciphertext, 'base64')
const salt = cipherBuffer.subarray(8, 16)
const keyDerivation = convertPassphraseToAesKeyBuffer(encryptionKey, salt)
const [key, iv] = [keyDerivation.subarray(0, 32), keyDerivation.subarray(32)]
const contents = cipherBuffer.subarray(16)
const decipher = createDecipheriv('aes-256-cbc', key, iv)
const decrypted = Buffer.concat([decipher.update(contents), decipher.final()])
return decrypted.toString('utf8')
} catch (e) {
throw e
}
}

/**
* Encrypts a text with the configured encryption key via ENCRYPTION_KEY env
* @param plaintext
*/
* Replicate CryptoJs.AES.encrypt method
* */
export function encrypt(plaintext: string): string {
return AES.encrypt(plaintext, encryptionKey).toString()
try {
const salt = randomBytes(8)
const keyDerivation = convertPassphraseToAesKeyBuffer(encryptionKey, salt)
const [key, iv] = [keyDerivation.subarray(0, 32), keyDerivation.subarray(32)]
const cipher = createCipheriv('aes-256-cbc', key, iv)
const contents = Buffer.concat([cipher.update(plaintext), cipher.final()])
const encrypted = Buffer.concat([Buffer.from('Salted__', 'utf8'), salt, contents])
return encrypted.toString('base64')
} catch (e) {
throw e
}
}
2 changes: 1 addition & 1 deletion src/internal/concurrency/stream.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Transform, TransformCallback } from 'stream'
import { Transform, TransformCallback } from 'node:stream'

export const createByteCounterStream = () => {
let bytes = 0
Expand Down
7 changes: 4 additions & 3 deletions src/internal/database/connection.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pg, { DatabaseError } from 'pg'
import { Knex, knex } from 'knex'
import pg from 'pg'
import { Knex } from 'knex'
import knex from 'knex'
import { JwtPayload } from 'jsonwebtoken'
import retry from 'async-retry'
import TTLCache from '@isaacs/ttlcache'
Expand Down Expand Up @@ -163,7 +164,7 @@ export class TenantConnection {
return await pool.transaction()
} catch (e) {
if (
e instanceof DatabaseError &&
e instanceof pg.DatabaseError &&
e.code === '08P01' &&
e.message.includes('no more connections allowed')
) {
Expand Down
16 changes: 8 additions & 8 deletions src/internal/database/migrations/migrate.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Client, ClientConfig } from 'pg'
import pg from 'pg'
import SQL from 'sql-template-strings'
import { loadMigrationFiles, MigrationError } from 'postgres-migrations'
import { getConfig, MultitenantMigrationStrategy } from '../../../config'
import { logger, logSchema } from '../../monitoring'
import { BasicPgClient, Migration } from 'postgres-migrations/dist/types'
import { validateMigrationHashes } from 'postgres-migrations/dist/validation'
import { runMigration } from 'postgres-migrations/dist/run-migration'
import type { BasicPgClient, Migration } from 'postgres-migrations/dist/types'
import { validateMigrationHashes } from 'postgres-migrations/dist/validation.js'
import { runMigration } from 'postgres-migrations/dist/run-migration.js'
import { searchPath } from '../connection'
import { getTenantConfig, listTenantsToMigrate } from '../tenant'
import { multitenantKnex } from '../multitenant-db'
Expand Down Expand Up @@ -179,7 +179,7 @@ export async function runMigrationsOnTenant(
tenantId?: string,
waitForLock = true
): Promise<void> {
let ssl: ClientConfig['ssl'] | undefined = undefined
let ssl: pg.ClientConfig['ssl'] | undefined = undefined

if (databaseSSLRootCert) {
ssl = { ca: databaseSSLRootCert }
Expand All @@ -202,7 +202,7 @@ export async function runMigrationsOnTenant(
async function connectAndMigrate(options: {
databaseUrl: string | undefined
migrationsDirectory: string
ssl?: ClientConfig['ssl']
ssl?: pg.ClientConfig['ssl']
shouldCreateStorageSchema?: boolean
tenantId?: string
waitForLock?: boolean
Expand All @@ -216,14 +216,14 @@ async function connectAndMigrate(options: {
waitForLock,
} = options

const dbConfig: ClientConfig = {
const dbConfig: pg.ClientConfig = {
connectionString: databaseUrl,
connectionTimeoutMillis: 60_000,
options: `-c search_path=${searchPath}`,
ssl,
}

const client = new Client(dbConfig)
const client = new pg.Client(dbConfig)
client.on('error', (err) => {
logSchema.error(logger, 'Error on database connection', {
type: 'error',
Expand Down
2 changes: 1 addition & 1 deletion src/internal/queue/database.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Db } from 'pg-boss'
import EventEmitter from 'events'
import EventEmitter from 'node:events'
import pg from 'pg'
import { ERRORS } from '@internal/errors'

Expand Down
2 changes: 1 addition & 1 deletion src/start/shutdown.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { logger, logSchema } from '@internal/monitoring'
import { AsyncAbortController } from '@internal/concurrency'
import { multitenantKnex, TenantConnection } from '@internal/database'
import http from 'http'
import http from 'node:http'

/**
* Binds shutdown handlers to the process
Expand Down
2 changes: 1 addition & 1 deletion src/storage/backend/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Readable } from 'stream'
import { Readable } from 'node:stream'
import { getConfig } from '../../config'

/**
Expand Down
8 changes: 4 additions & 4 deletions src/storage/backend/file.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as xattr from 'fs-xattr'
import fs from 'fs-extra'
import path from 'path'
import path from 'node:path'
import fileChecksum from 'md5-file'
import { promisify } from 'util'
import stream from 'stream'
import { promisify } from 'node:util'
import stream from 'node:stream'
import MultiStream from 'multistream'
import { getConfig } from '../../config'
import {
Expand All @@ -15,7 +15,7 @@ import {
UploadPart,
} from './adapter'
import { ERRORS, StorageBackendError } from '@internal/errors'
import { randomUUID } from 'crypto'
import { randomUUID } from 'node:crypto'
import fsExtra from 'fs-extra'
const pipeline = promisify(stream.pipeline)

Expand Down
1 change: 1 addition & 0 deletions src/storage/backend/s3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ export class S3Backend implements StorageBackendAdapter {
const params: S3ClientConfig = {
region: options.region,
runtime: 'node',
cacheMiddleware: true,
requestHandler: new NodeHttpHandler({
httpAgent: options.httpAgent?.httpAgent,
httpsAgent: options.httpAgent?.httpsAgent,
Expand Down
2 changes: 1 addition & 1 deletion src/storage/protocols/s3/byte-limit-stream.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Transform, TransformCallback } from 'stream'
import { Transform, TransformCallback } from 'node:stream'
import { ERRORS } from '@internal/errors'

export class ByteLimitTransformStream extends Transform {
Expand Down
4 changes: 2 additions & 2 deletions src/storage/protocols/s3/s3-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import {
UploadPartCommandInput,
UploadPartCopyCommandInput,
} from '@aws-sdk/client-s3'
import { PassThrough, Readable } from 'stream'
import stream from 'stream/promises'
import { PassThrough, Readable } from 'node:stream'
import stream from 'node:stream/promises'
import { getFileSizeLimit, mustBeValidBucketName, mustBeValidKey } from '../../limits'
import { ERRORS } from '@internal/errors'
import { S3MultipartUpload, Obj } from '../../schemas'
Expand Down
2 changes: 1 addition & 1 deletion src/storage/protocols/s3/signature-v4.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import crypto from 'crypto'
import crypto from 'node:crypto'
import { ERRORS } from '@internal/errors'

interface SignatureV4Options {
Expand Down
2 changes: 1 addition & 1 deletion src/storage/protocols/tus/als-memory-kv.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AsyncLocalStorage } from 'async_hooks'
import { AsyncLocalStorage } from 'node:async_hooks'
import { KvStore } from '@tus/server'
import { MetadataValue } from '@tus/s3-store'

Expand Down
2 changes: 1 addition & 1 deletion src/storage/protocols/tus/file-store.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FileStore as TusFileStore } from '@tus/file-store'
import { Upload } from '@tus/server'
import fsExtra from 'fs-extra'
import path from 'path'
import path from 'node:path'
import { Configstore } from '@tus/file-store'
import { FileBackend } from '../../backend'

Expand Down
4 changes: 2 additions & 2 deletions src/storage/protocols/tus/postgres-locker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Lock, Locker, RequestRelease } from '@tus/server'
import { clearTimeout } from 'timers'
import EventEmitter from 'events'
import { clearTimeout } from 'node:timers'
import EventEmitter from 'node:events'
import { Database, DBError } from '../../database'
import { PubSubAdapter } from '@internal/pubsub'
import { UploadId } from './upload-id'
Expand Down
2 changes: 1 addition & 1 deletion src/storage/renderer/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { FastifyRequest } from 'fastify'
import { Renderer, RenderOptions } from './renderer'
import axiosRetry from 'axios-retry'
import { ERRORS } from '@internal/errors'
import { Stream } from 'stream'
import { Stream } from 'node:stream'
import Agent from 'agentkeepalive'

/**
Expand Down
2 changes: 1 addition & 1 deletion src/storage/renderer/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FastifyReply, FastifyRequest } from 'fastify'
import { ObjectMetadata } from '../backend'
import { Readable } from 'stream'
import { Readable } from 'node:stream'
import { getConfig } from '../../config'
import { Obj } from '../schemas'

Expand Down
2 changes: 1 addition & 1 deletion src/storage/uploader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { randomUUID } from 'crypto'
import { randomUUID } from 'node:crypto'
import { FastifyRequest } from 'fastify'

import { ERRORS } from '@internal/errors'
Expand Down
Loading