Adding working board
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { CreateBucketCommand, GetObjectCommand, HeadBucketCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
|
||||
import { Readable } from 'node:stream'
|
||||
|
||||
export type ObjectBody = { stream: Readable; contentLength?: number }
|
||||
|
||||
export interface ObjectStorage {
|
||||
readonly bucket: string
|
||||
readonly provider: 's3' | 'memory'
|
||||
initialize(): Promise<void>
|
||||
putObject(key: string, body: Buffer, contentType: string): Promise<{ etag?: string }>
|
||||
getObject(key: string): Promise<ObjectBody | null>
|
||||
}
|
||||
|
||||
export class MemoryObjectStorage implements ObjectStorage {
|
||||
readonly bucket: string
|
||||
readonly provider = 'memory' as const
|
||||
private readonly objects = new Map<string, Buffer>()
|
||||
|
||||
constructor(bucket = 'osint-test-assets') { this.bucket = bucket }
|
||||
async initialize() { /* Nothing to initialize. */ }
|
||||
async putObject(key: string, body: Buffer) { this.objects.set(key, Buffer.from(body)); return {} }
|
||||
async getObject(key: string) {
|
||||
const body = this.objects.get(key)
|
||||
return body ? { stream: Readable.from(body), contentLength: body.byteLength } : null
|
||||
}
|
||||
}
|
||||
|
||||
export class S3ObjectStorage implements ObjectStorage {
|
||||
readonly provider = 's3' as const
|
||||
readonly bucket: string
|
||||
private readonly client: S3Client
|
||||
|
||||
constructor(options: { endpoint: string; region: string; accessKey: string; secretKey: string; bucket: string; forcePathStyle: boolean }) {
|
||||
this.bucket = options.bucket
|
||||
this.client = new S3Client({
|
||||
endpoint: options.endpoint,
|
||||
region: options.region,
|
||||
forcePathStyle: options.forcePathStyle,
|
||||
credentials: { accessKeyId: options.accessKey, secretAccessKey: options.secretKey },
|
||||
})
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
try {
|
||||
await this.client.send(new HeadBucketCommand({ Bucket: this.bucket }))
|
||||
} catch (error) {
|
||||
const status = (error as { $metadata?: { httpStatusCode?: number } }).$metadata?.httpStatusCode
|
||||
if (status !== 404) throw error
|
||||
try { await this.client.send(new CreateBucketCommand({ Bucket: this.bucket })) }
|
||||
catch (createError) {
|
||||
const createStatus = (createError as { $metadata?: { httpStatusCode?: number } }).$metadata?.httpStatusCode
|
||||
if (createStatus !== 409) throw createError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async putObject(key: string, body: Buffer, contentType: string) {
|
||||
const result = await this.client.send(new PutObjectCommand({ Bucket: this.bucket, Key: key, Body: body, ContentType: contentType }))
|
||||
return { etag: result.ETag?.replaceAll('"', '') }
|
||||
}
|
||||
|
||||
async getObject(key: string) {
|
||||
try {
|
||||
const result = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: key }))
|
||||
if (!result.Body || typeof (result.Body as NodeJS.ReadableStream).pipe !== 'function') throw new Error(`Object ${key} did not return a Node stream`)
|
||||
return { stream: result.Body as Readable, contentLength: result.ContentLength }
|
||||
} catch (error) {
|
||||
const status = (error as { $metadata?: { httpStatusCode?: number } }).$metadata?.httpStatusCode
|
||||
if (status === 404) return null
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createObjectStorageFromEnv() {
|
||||
if (process.env.ASSET_STORAGE_DRIVER === 'memory' || process.env.NODE_ENV === 'test') return new MemoryObjectStorage(process.env.S3_BUCKET)
|
||||
const accessKey = process.env.S3_ACCESS_KEY
|
||||
const secretKey = process.env.S3_SECRET_KEY
|
||||
if (!accessKey || !secretKey) throw new Error('S3_ACCESS_KEY and S3_SECRET_KEY are required for MinIO asset storage')
|
||||
return new S3ObjectStorage({
|
||||
endpoint: process.env.S3_ENDPOINT || 'http://127.0.0.1:9000',
|
||||
region: process.env.S3_REGION || 'us-east-1',
|
||||
accessKey,
|
||||
secretKey,
|
||||
bucket: process.env.S3_BUCKET || 'osint-evidence',
|
||||
forcePathStyle: process.env.S3_FORCE_PATH_STYLE !== 'false',
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user