Skip to content

Commit 4d15d8a

Browse files
committed
🔧 fix: strictly check protocol
1 parent 9b9eb92 commit 4d15d8a

File tree

5 files changed

+77
-36
lines changed

5 files changed

+77
-36
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 1.3.2 - 15 May 2025
2+
Bug fix:
3+
- [#65](https://github.com/elysiajs/elysia-cors/issues/65) strictly check origin protocol
4+
15
# 1.3.1 - 8 May 2025
26
Bug fix:
37
- strictly check origin not using sub includes

example/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ import { cors } from '../src/index'
44
const app = new Elysia()
55
.use(
66
cors({
7-
origin: 'example.com'
7+
origin: 'http://example.com'
88
})
99
)
1010
.post('/', ({ body }) => body)
1111

1212
app.handle(
1313
new Request('http://localhost/awd', {
1414
headers: {
15-
origin: 'http://notexample.com'
15+
origin: 'https://example.com',
16+
a: 'b',
17+
c: 'd'
1618
}
1719
})
1820
)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@elysiajs/cors",
3-
"version": "1.3.1",
3+
"version": "1.3.2",
44
"description": "Plugin for Elysia that for Cross Origin Requests (CORs)",
55
"author": {
66
"name": "saltyAom",

src/index.ts

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -168,44 +168,21 @@ const isBun = typeof new Headers()?.toJSON === 'function'
168168
* Attempts to process headers based on request headers.
169169
*/
170170
const processHeaders = (headers: Headers) => {
171-
if (isBun) return Object.keys(headers.toJSON()).join(', ')
171+
// if (isBun) return Object.keys(headers.toJSON()).join(', ')
172172

173173
let keys = ''
174174

175+
let i = 0
175176
headers.forEach((_, key) => {
176-
keys += key + ', '
177-
})
177+
if (i) keys = keys + ', ' + key
178+
else keys = key
178179

179-
if (keys) keys = keys.slice(0, -1)
180+
i++
181+
})
180182

181183
return keys
182184
}
183185

184-
const processOrigin = (
185-
origin: Origin,
186-
request: Request,
187-
from: string
188-
): boolean => {
189-
if (Array.isArray(origin))
190-
return origin.some((o) => processOrigin(o, request, from))
191-
192-
switch (typeof origin) {
193-
case 'string':
194-
const fromProtocol = from.indexOf('://')
195-
if (fromProtocol !== -1) from = from.slice(fromProtocol + 3)
196-
197-
return origin === from
198-
199-
case 'function':
200-
return origin(request) === true
201-
202-
case 'object':
203-
if (origin instanceof RegExp) return origin.test(from)
204-
}
205-
206-
return false
207-
}
208-
209186
export const cors = (config?: CORSConfig) => {
210187
let {
211188
aot = true,
@@ -238,6 +215,38 @@ export const cors = (config?: CORSConfig) => {
238215

239216
const anyOrigin = origins?.some((o) => o === '*')
240217

218+
const originMap = <Record<string, true>>{}
219+
if (origins)
220+
for (const origin of origins)
221+
if (typeof origin === 'string') originMap[origin] = true
222+
223+
const processOrigin = (
224+
origin: Origin,
225+
request: Request,
226+
from: string
227+
): boolean => {
228+
if (Array.isArray(origin))
229+
return origin.some((o) => processOrigin(o, request, from))
230+
231+
switch (typeof origin) {
232+
case 'string':
233+
if (from in originMap) return true
234+
235+
const fromProtocol = from.indexOf('://')
236+
if (fromProtocol !== -1) from = from.slice(fromProtocol + 3)
237+
238+
return origin === from
239+
240+
case 'function':
241+
return origin(request) === true
242+
243+
case 'object':
244+
if (origin instanceof RegExp) return origin.test(from)
245+
}
246+
247+
return false
248+
}
249+
241250
const handleOrigin = (set: Context['set'], request: Request) => {
242251
// origin === `true` means any origin
243252
if (origin === true) {
@@ -269,9 +278,6 @@ export const cors = (config?: CORSConfig) => {
269278

270279
return
271280
}
272-
273-
// value can be string (truthy value) but not `true`
274-
if (value) headers.push(value)
275281
}
276282
}
277283

@@ -339,7 +345,6 @@ export const cors = (config?: CORSConfig) => {
339345
handleMethod(set, request.method)
340346

341347
if (allowedHeaders === true || exposeHeaders === true) {
342-
// @ts-ignore
343348
const headers = processHeaders(request.headers)
344349

345350
if (allowedHeaders === true)

test/origin.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,34 @@ describe('Origin', () => {
144144

145145
expect(response.headers.has('access-control-allow-origin')).toBeFalse()
146146
})
147+
148+
it('strictly check protocol', async () => {
149+
const app = new Elysia()
150+
.use(
151+
cors({
152+
origin: 'http://example.com'
153+
})
154+
)
155+
.post('/', ({ body }) => body)
156+
157+
const pass = await app.handle(
158+
new Request('http://localhost/awd', {
159+
headers: {
160+
origin: 'http://example.com'
161+
}
162+
})
163+
)
164+
165+
expect(pass.headers.has('access-control-allow-origin')).toBeTrue()
166+
167+
const fail = await app.handle(
168+
new Request('http://localhost/awd', {
169+
headers: {
170+
origin: 'https://example.com'
171+
}
172+
})
173+
)
174+
175+
expect(fail.headers.has('access-control-allow-origin')).toBeFalse()
176+
})
147177
})

0 commit comments

Comments
 (0)