Skip to content

Commit 2e6c4ac

Browse files
committed
Merge branch 'master' of https://github.com/supabase/storage-api
2 parents 1251eb0 + ddfbcda commit 2e6c4ac

File tree

3 files changed

+80
-48
lines changed

3 files changed

+80
-48
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"prettier:check": "prettier -c src/**",
1818
"eslint:check": "eslint 'src/**'",
1919
"stop:db": "docker-compose --project-dir . -f src/test/db/docker-compose.yml down --remove-orphans",
20-
"restart:db": "docker-compose --project-dir . -f src/test/db/docker-compose.yml down && docker-compose --project-dir . -f src/test/db/docker-compose.yml up -d && sleep 1 && npm run migration:run"
20+
"restart:db": "docker-compose --project-dir . -f src/test/db/docker-compose.yml down && docker-compose --project-dir . -f src/test/db/docker-compose.yml up -d && sleep 5 && npm run migration:run"
2121
},
2222
"author": "Supabase",
2323
"license": "ISC",

src/routes/object/getObject.ts

+74-42
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { FastifyInstance } from 'fastify'
1+
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
22
import { FromSchema } from 'json-schema-to-ts'
3+
import { IncomingMessage, Server, ServerResponse } from 'http'
34
import { AuthenticatedRequest, Obj } from '../../types/types'
45
import { getPostgrestClient, isValidKey, transformPostgrestError } from '../../utils'
56
import { getConfig } from '../../utils/config'
@@ -21,11 +22,64 @@ interface getObjectRequestInterface extends AuthenticatedRequest {
2122
Params: FromSchema<typeof getObjectParamsSchema>
2223
}
2324

25+
async function requestHandler(
26+
request: FastifyRequest<getObjectRequestInterface, Server, IncomingMessage>,
27+
response: FastifyReply<
28+
Server,
29+
IncomingMessage,
30+
ServerResponse,
31+
getObjectRequestInterface,
32+
unknown
33+
>
34+
) {
35+
const authHeader = request.headers.authorization
36+
const jwt = authHeader.substring('Bearer '.length)
37+
38+
const postgrest = getPostgrestClient(jwt)
39+
40+
const { bucketName } = request.params
41+
const objectName = request.params['*']
42+
43+
if (!isValidKey(objectName) || !isValidKey(bucketName)) {
44+
return response
45+
.status(400)
46+
.send(createResponse('The key contains invalid characters', '400', 'Invalid key'))
47+
}
48+
49+
const objectResponse = await postgrest
50+
.from<Obj>('objects')
51+
.select('id')
52+
.match({
53+
name: objectName,
54+
bucket_id: bucketName,
55+
})
56+
.single()
57+
58+
if (objectResponse.error) {
59+
const { status, error } = objectResponse
60+
request.log.error({ error }, 'error object')
61+
return response.status(400).send(transformPostgrestError(error, status))
62+
}
63+
64+
// send the object from s3
65+
const s3Key = `${projectRef}/${bucketName}/${objectName}`
66+
request.log.info(s3Key)
67+
const data = await getObject(client, globalS3Bucket, s3Key)
68+
69+
return response
70+
.status(data.$metadata.httpStatusCode ?? 200)
71+
.header('Content-Type', data.ContentType)
72+
.header('Cache-Control', data.CacheControl)
73+
.header('ETag', data.ETag)
74+
.header('Last-Modified', data.LastModified)
75+
.send(data.Body)
76+
}
77+
2478
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
2579
export default async function routes(fastify: FastifyInstance) {
2680
const summary = 'Retrieve an object'
2781
fastify.get<getObjectRequestInterface>(
28-
'/:bucketName/*',
82+
'/authenticated/:bucketName/*',
2983
{
3084
// @todo add success response schema here
3185
schema: {
@@ -37,47 +91,25 @@ export default async function routes(fastify: FastifyInstance) {
3791
},
3892
},
3993
async (request, response) => {
40-
const authHeader = request.headers.authorization
41-
const jwt = authHeader.substring('Bearer '.length)
42-
43-
const postgrest = getPostgrestClient(jwt)
44-
45-
const { bucketName } = request.params
46-
const objectName = request.params['*']
47-
48-
if (!isValidKey(objectName) || !isValidKey(bucketName)) {
49-
return response
50-
.status(400)
51-
.send(createResponse('The key contains invalid characters', '400', 'Invalid key'))
52-
}
53-
54-
const objectResponse = await postgrest
55-
.from<Obj>('objects')
56-
.select('id')
57-
.match({
58-
name: objectName,
59-
bucket_id: bucketName,
60-
})
61-
.single()
62-
63-
if (objectResponse.error) {
64-
const { status, error } = objectResponse
65-
request.log.error({ error }, 'error object')
66-
return response.status(400).send(transformPostgrestError(error, status))
67-
}
68-
69-
// send the object from s3
70-
const s3Key = `${projectRef}/${bucketName}/${objectName}`
71-
request.log.info(s3Key)
72-
const data = await getObject(client, globalS3Bucket, s3Key)
94+
return requestHandler(request, response)
95+
}
96+
)
7397

74-
return response
75-
.status(data.$metadata.httpStatusCode ?? 200)
76-
.header('Content-Type', data.ContentType)
77-
.header('Cache-Control', data.CacheControl)
78-
.header('ETag', data.ETag)
79-
.header('Last-Modified', data.LastModified)
80-
.send(data.Body)
98+
// to be deprecated
99+
fastify.get<getObjectRequestInterface>(
100+
'/:bucketName/*',
101+
{
102+
// @todo add success response schema here
103+
schema: {
104+
params: getObjectParamsSchema,
105+
headers: { $ref: 'authSchema#' },
106+
summary: 'Deprecated (use /authenticated/bucketName/object instead): Retrieve an object',
107+
response: { '4xx': { $ref: 'errorSchema#' } },
108+
tags: ['object'],
109+
},
110+
},
111+
async (request, response) => {
112+
return requestHandler(request, response)
81113
}
82114
)
83115
}

src/test/object.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ describe('testing GET object', () => {
9494
test('check if RLS policies are respected: authenticated user is able to read authenticated resource', async () => {
9595
const response = await app().inject({
9696
method: 'GET',
97-
url: '/object/bucket2/authenticated/casestudy.png',
97+
url: '/object/authenticated/bucket2/authenticated/casestudy.png',
9898
headers: {
9999
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
100100
},
@@ -106,7 +106,7 @@ describe('testing GET object', () => {
106106
test('check if RLS policies are respected: anon user is not able to read authenticated resource', async () => {
107107
const response = await app().inject({
108108
method: 'GET',
109-
url: '/object/bucket2/authenticated/casestudy.png',
109+
url: '/object/authenticated/bucket2/authenticated/casestudy.png',
110110
headers: {
111111
authorization: `Bearer ${anonKey}`,
112112
},
@@ -118,7 +118,7 @@ describe('testing GET object', () => {
118118
test('user is not able to read a resource without Auth header', async () => {
119119
const response = await app().inject({
120120
method: 'GET',
121-
url: '/object/bucket2/authenticated/casestudy.png',
121+
url: '/object/authenticated/bucket2/authenticated/casestudy.png',
122122
})
123123
expect(response.statusCode).toBe(400)
124124
expect(mockGetObject).not.toHaveBeenCalled()
@@ -127,7 +127,7 @@ describe('testing GET object', () => {
127127
test('return 400 when reading a non existent object', async () => {
128128
const response = await app().inject({
129129
method: 'GET',
130-
url: '/object/bucket2/authenticated/notfound',
130+
url: '/object/authenticated/bucket2/authenticated/notfound',
131131
headers: {
132132
authorization: `Bearer ${anonKey}`,
133133
},
@@ -139,7 +139,7 @@ describe('testing GET object', () => {
139139
test('return 400 when reading a non existent bucket', async () => {
140140
const response = await app().inject({
141141
method: 'GET',
142-
url: '/object/notfound/authenticated/casestudy.png',
142+
url: '/object/authenticated/notfound/authenticated/casestudy.png',
143143
headers: {
144144
authorization: `Bearer ${anonKey}`,
145145
},

0 commit comments

Comments
 (0)