Projektstart
This commit is contained in:
8
backend/node_modules/@fastify/cors/.editorconfig
generated
vendored
Normal file
8
backend/node_modules/@fastify/cors/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
5
backend/node_modules/@fastify/cors/.gitattributes
generated
vendored
Normal file
5
backend/node_modules/@fastify/cors/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set
|
||||
* text=auto
|
||||
|
||||
# Require Unix line endings
|
||||
* text eol=lf
|
||||
16
backend/node_modules/@fastify/cors/.github/dependabot.yml
generated
vendored
Normal file
16
backend/node_modules/@fastify/cors/.github/dependabot.yml
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
- dependency-name: tap
|
||||
update-types: ["version-update:semver-major"]
|
||||
21
backend/node_modules/@fastify/cors/.github/stale.yml
generated
vendored
Normal file
21
backend/node_modules/@fastify/cors/.github/stale.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 15
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- "discussion"
|
||||
- "feature request"
|
||||
- "bug"
|
||||
- "help wanted"
|
||||
- "plugin suggestion"
|
||||
- "good first issue"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
23
backend/node_modules/@fastify/cors/.github/workflows/ci.yml
generated
vendored
Normal file
23
backend/node_modules/@fastify/cors/.github/workflows/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- next
|
||||
- 'v*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v3
|
||||
with:
|
||||
lint: true
|
||||
license-check: true
|
||||
4
backend/node_modules/@fastify/cors/.taprc
generated
vendored
Normal file
4
backend/node_modules/@fastify/cors/.taprc
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
ts: false
|
||||
jsx: false
|
||||
coverage: true
|
||||
flow: true
|
||||
21
backend/node_modules/@fastify/cors/LICENSE
generated
vendored
Normal file
21
backend/node_modules/@fastify/cors/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Fastify
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
169
backend/node_modules/@fastify/cors/README.md
generated
vendored
Normal file
169
backend/node_modules/@fastify/cors/README.md
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
# @fastify/cors
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/@fastify/cors)
|
||||
[](https://standardjs.com/)
|
||||
|
||||
|
||||
`@fastify/cors` enables the use of [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) in a Fastify application.
|
||||
|
||||
## Install
|
||||
```
|
||||
npm i @fastify/cors
|
||||
```
|
||||
|
||||
### Compatibility
|
||||
|
||||
| Plugin version | Fastify version |
|
||||
| -------------- |---------------- |
|
||||
| `^8.0.0` | `^4.0.0` |
|
||||
| `^7.0.0` | `^3.0.0` |
|
||||
| `^3.0.0` | `^2.0.0` |
|
||||
| `^1.0.0` | `^1.0.0` |
|
||||
|
||||
|
||||
Please note that if a Fastify version is out of support, then so are the corresponding version(s) of this plugin
|
||||
in the table above.
|
||||
See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.
|
||||
|
||||
## Usage
|
||||
Require `@fastify/cors` and register it as any other plugin, it will add an `onRequest` hook and a [wildcard options route](https://github.com/fastify/fastify/issues/326#issuecomment-411360862).
|
||||
```js
|
||||
import Fastify from 'fastify'
|
||||
import cors from '@fastify/cors'
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, {
|
||||
// put your options here
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 3000 })
|
||||
```
|
||||
You can use it as is without passing any option or you can configure it as explained below.
|
||||
### Options
|
||||
* `origin`: Configures the **Access-Control-Allow-Origin** CORS header. The value of origin could be of different types:
|
||||
- `Boolean` - set `origin` to `true` to reflect the [request origin](http://tools.ietf.org/html/draft-abarth-origin-09), or set it to `false` to disable CORS.
|
||||
- `String` - set `origin` to a specific origin. For example if you set it to `"http://example.com"` only requests from "http://example.com" will be allowed. The special `*` value (default) allows any origin.
|
||||
- `RegExp` - set `origin` to a regular expression pattern that will be used to test the request origin. If it is a match, the request origin will be reflected. For example, the pattern `/example\.com$/` will reflect any request that is coming from an origin ending with "example.com".
|
||||
- `Array` - set `origin` to an array of valid origins. Each origin can be a `String` or a `RegExp`. For example `["http://example1.com", /\.example2\.com$/]` will accept any request from "http://example1.com" or from a subdomain of "example2.com".
|
||||
- `Function` - set `origin` to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback as a second (which expects the signature `err [Error | null], origin`), where `origin` is a non-function value of the origin option. *Async-await* and promises are supported as well. The Fastify instance is bound to function call and you may access via `this`. For example:
|
||||
```js
|
||||
origin: (origin, cb) => {
|
||||
const hostname = new URL(origin).hostname
|
||||
if(hostname === "localhost"){
|
||||
// Request from localhost will pass
|
||||
cb(null, true)
|
||||
return
|
||||
}
|
||||
// Generate an error on other origins, disabling access
|
||||
cb(new Error("Not allowed"), false)
|
||||
}
|
||||
```
|
||||
* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`).
|
||||
* `hook`: See the section `Custom Fastify hook name` (default: `onRequest`)
|
||||
* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: `'Content-Type,Authorization'`) or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header.
|
||||
* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: `'Content-Range,X-Content-Range'`) or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed.
|
||||
* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted.
|
||||
* `maxAge`: Configures the **Access-Control-Max-Age** CORS header. In seconds. Set to an integer to pass the header, otherwise it is omitted.
|
||||
* `cacheControl`: Configures the **Cache-Control** header for CORS preflight responses. Set to an integer to pass the header as `Cache-Control: max-age=${cacheControl}`, or set to a string to pass the header as `Cache-Control: ${cacheControl}` (fully define the header value), otherwise the header is omitted.
|
||||
* `preflightContinue`: Pass the CORS preflight response to the route handler (default: `false`).
|
||||
* `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`.
|
||||
* `preflight`: if needed you can entirely disable preflight by passing `false` here (default: `true`).
|
||||
* `strictPreflight`: Enforces strict requirement of the CORS preflight request headers (**Access-Control-Request-Method** and **Origin**) as defined by the [W3C CORS specification](https://www.w3.org/TR/2020/SPSD-cors-20200602/#resource-preflight-requests) (the current [fetch living specification](https://fetch.spec.whatwg.org/) does not define server behavior for missing headers). Preflight requests without the required headers will result in 400 errors when set to `true` (default: `true`).
|
||||
* `hideOptionsRoute`: hide options route from the documentation built using [@fastify/swagger](https://github.com/fastify/fastify-swagger) (default: `true`).
|
||||
|
||||
### Configuring CORS Asynchronously
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')()
|
||||
|
||||
fastify.register(require('@fastify/cors'), (instance) => {
|
||||
return (req, callback) => {
|
||||
const corsOptions = {
|
||||
// This is NOT recommended for production as it enables reflection exploits
|
||||
origin: true
|
||||
};
|
||||
|
||||
// do not include CORS headers for requests from localhost
|
||||
if (/^localhost$/m.test(req.headers.origin)) {
|
||||
corsOptions.origin = false
|
||||
}
|
||||
|
||||
// callback expects two parameters: error and options
|
||||
callback(null, corsOptions)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.register(async function (fastify) {
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
### Custom Fastify hook name
|
||||
|
||||
By default, `@fastify/cors` adds a `onRequest` hook where the validation and header injection are executed. This can be customized by passing `hook` in the options. Valid values are `onRequest`, `preParsing`, `preValidation`, `preHandler`, `preSerialization`, and `onSend`.
|
||||
|
||||
```js
|
||||
import Fastify from 'fastify'
|
||||
import cors from '@fastify/cors'
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, {
|
||||
hook: 'preHandler',
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
When configuring CORS asynchronously, an object with `delegator` key is expected:
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')()
|
||||
|
||||
fastify.register(require('@fastify/cors'), {
|
||||
hook: 'preHandler',
|
||||
delegator: (req, callback) => {
|
||||
const corsOptions = {
|
||||
// This is NOT recommended for production as it enables reflection exploits
|
||||
origin: true
|
||||
};
|
||||
|
||||
// do not include CORS headers for requests from localhost
|
||||
if (/^localhost$/m.test(req.headers.origin)) {
|
||||
corsOptions.origin = false
|
||||
}
|
||||
|
||||
// callback expects two parameters: error and options
|
||||
callback(null, corsOptions)
|
||||
},
|
||||
})
|
||||
|
||||
fastify.register(async function (fastify) {
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
The code is a port for Fastify of [`expressjs/cors`](https://github.com/expressjs/cors).
|
||||
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).<br/>
|
||||
[`expressjs/cors` license](https://github.com/expressjs/cors/blob/master/LICENSE)
|
||||
17
backend/node_modules/@fastify/cors/bench.js
generated
vendored
Normal file
17
backend/node_modules/@fastify/cors/bench.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
const fastify = require('fastify')()
|
||||
|
||||
fastify.register((instance, opts, next) => {
|
||||
instance.register(require('./index'))
|
||||
instance.get('/fastify', (req, reply) => reply.send('ok'))
|
||||
next()
|
||||
})
|
||||
|
||||
fastify.register((instance, opts, next) => {
|
||||
instance.use(require('cors')())
|
||||
instance.get('/express', (req, reply) => reply.send('ok'))
|
||||
next()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 3000 })
|
||||
15
backend/node_modules/@fastify/cors/benchmark/package.json
generated
vendored
Normal file
15
backend/node_modules/@fastify/cors/benchmark/package.json
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "benchmark",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "vary.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"benchmark": "^2.1.4",
|
||||
"vary": "^1.1.2"
|
||||
}
|
||||
}
|
||||
34
backend/node_modules/@fastify/cors/benchmark/vary.js
generated
vendored
Normal file
34
backend/node_modules/@fastify/cors/benchmark/vary.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const vary = require('vary')
|
||||
const createAddFieldnameToVary = require('../vary').createAddFieldnameToVary
|
||||
|
||||
const replyMock = (header) => ({
|
||||
getHeader () { return header },
|
||||
setHeader () { },
|
||||
header () { }
|
||||
})
|
||||
|
||||
const addAcceptToVary = createAddFieldnameToVary('Accept')
|
||||
const addWildcardToVary = createAddFieldnameToVary('*')
|
||||
const addAcceptEncodingToVary = createAddFieldnameToVary('Accept-Encoding')
|
||||
const addXFooToVary = createAddFieldnameToVary('X-Foo')
|
||||
|
||||
new benchmark.Suite()
|
||||
.add('vary - field to undefined', function () { vary(replyMock(undefined), 'Accept-Encoding') }, { minSamples: 100 })
|
||||
.add('vary - field to *', function () { vary(replyMock('*'), 'Accept-Encoding') }, { minSamples: 100 })
|
||||
.add('vary - * to field', function () { vary(replyMock('Accept-Encoding'), '*') }, { minSamples: 100 })
|
||||
.add('vary - field to empty', function () { vary(replyMock(''), 'Accept-Encoding') }, { minSamples: 100 })
|
||||
.add('vary - fields string to empty', function () { vary(replyMock(''), 'Accept') }, { minSamples: 100 })
|
||||
.add('vary - field to fields', function () { vary(replyMock('Accept, Accept-Encoding, Accept-Language'), 'X-Foo') }, { minSamples: 100 })
|
||||
|
||||
.add('cors - field to undefined', function () { addAcceptEncodingToVary(replyMock(undefined)) }, { minSamples: 100 })
|
||||
.add('cors - field to *', function () { addAcceptEncodingToVary(replyMock('*')) }, { minSamples: 100 })
|
||||
.add('cors - * to field', function () { addWildcardToVary(replyMock('Accept-Encoding')) }, { minSamples: 100 })
|
||||
.add('cors - field to empty', function () { addAcceptEncodingToVary(replyMock('')) }, { minSamples: 100 })
|
||||
.add('cors - fields string to empty', function () { addAcceptToVary(replyMock('')) }, { minSamples: 100 })
|
||||
.add('cors - field to fields', function () { addXFooToVary(replyMock('Accept, Accept-Encoding, Accept-Language')) }, { minSamples: 100 })
|
||||
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
307
backend/node_modules/@fastify/cors/index.js
generated
vendored
Normal file
307
backend/node_modules/@fastify/cors/index.js
generated
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
'use strict'
|
||||
|
||||
const fp = require('fastify-plugin')
|
||||
const {
|
||||
addAccessControlRequestHeadersToVaryHeader,
|
||||
addOriginToVaryHeader
|
||||
} = require('./vary')
|
||||
|
||||
const defaultOptions = {
|
||||
origin: '*',
|
||||
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
hook: 'onRequest',
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 204,
|
||||
credentials: false,
|
||||
exposedHeaders: null,
|
||||
allowedHeaders: null,
|
||||
maxAge: null,
|
||||
preflight: true,
|
||||
strictPreflight: true
|
||||
}
|
||||
|
||||
const validHooks = [
|
||||
'onRequest',
|
||||
'preParsing',
|
||||
'preValidation',
|
||||
'preHandler',
|
||||
'preSerialization',
|
||||
'onSend'
|
||||
]
|
||||
|
||||
const hookWithPayload = [
|
||||
'preSerialization',
|
||||
'preParsing',
|
||||
'onSend'
|
||||
]
|
||||
|
||||
function validateHook (value, next) {
|
||||
if (validHooks.indexOf(value) !== -1) {
|
||||
return
|
||||
}
|
||||
next(new TypeError('@fastify/cors: Invalid hook option provided.'))
|
||||
}
|
||||
|
||||
function fastifyCors (fastify, opts, next) {
|
||||
fastify.decorateRequest('corsPreflightEnabled', false)
|
||||
|
||||
let hideOptionsRoute = true
|
||||
if (typeof opts === 'function') {
|
||||
handleCorsOptionsDelegator(opts, fastify, { hook: defaultOptions.hook }, next)
|
||||
} else if (opts.delegator) {
|
||||
const { delegator, ...options } = opts
|
||||
handleCorsOptionsDelegator(delegator, fastify, options, next)
|
||||
} else {
|
||||
if (opts.hideOptionsRoute !== undefined) hideOptionsRoute = opts.hideOptionsRoute
|
||||
const corsOptions = normalizeCorsOptions(opts)
|
||||
validateHook(corsOptions.hook, next)
|
||||
if (hookWithPayload.indexOf(corsOptions.hook) !== -1) {
|
||||
fastify.addHook(corsOptions.hook, function handleCors (req, reply, payload, next) {
|
||||
addCorsHeadersHandler(fastify, corsOptions, req, reply, next)
|
||||
})
|
||||
} else {
|
||||
fastify.addHook(corsOptions.hook, function handleCors (req, reply, next) {
|
||||
addCorsHeadersHandler(fastify, corsOptions, req, reply, next)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// The preflight reply must occur in the hook. This allows fastify-cors to reply to
|
||||
// preflight requests BEFORE possible authentication plugins. If the preflight reply
|
||||
// occurred in this handler, other plugins may deny the request since the browser will
|
||||
// remove most headers (such as the Authentication header).
|
||||
//
|
||||
// This route simply enables fastify to accept preflight requests.
|
||||
fastify.options('*', { schema: { hide: hideOptionsRoute } }, (req, reply) => {
|
||||
if (!req.corsPreflightEnabled) {
|
||||
// Do not handle preflight requests if the origin option disabled CORS
|
||||
reply.callNotFound()
|
||||
return
|
||||
}
|
||||
|
||||
reply.send()
|
||||
})
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
function handleCorsOptionsDelegator (optionsResolver, fastify, opts, next) {
|
||||
const hook = (opts && opts.hook) || defaultOptions.hook
|
||||
validateHook(hook, next)
|
||||
if (optionsResolver.length === 2) {
|
||||
if (hookWithPayload.indexOf(hook) !== -1) {
|
||||
fastify.addHook(hook, function handleCors (req, reply, payload, next) {
|
||||
handleCorsOptionsCallbackDelegator(optionsResolver, fastify, req, reply, next)
|
||||
})
|
||||
} else {
|
||||
fastify.addHook(hook, function handleCors (req, reply, next) {
|
||||
handleCorsOptionsCallbackDelegator(optionsResolver, fastify, req, reply, next)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (hookWithPayload.indexOf(hook) !== -1) {
|
||||
// handle delegator based on Promise
|
||||
fastify.addHook(hook, function handleCors (req, reply, payload, next) {
|
||||
const ret = optionsResolver(req)
|
||||
if (ret && typeof ret.then === 'function') {
|
||||
ret.then(options => addCorsHeadersHandler(fastify, normalizeCorsOptions(options, true), req, reply, next)).catch(next)
|
||||
return
|
||||
}
|
||||
next(new Error('Invalid CORS origin option'))
|
||||
})
|
||||
} else {
|
||||
// handle delegator based on Promise
|
||||
fastify.addHook(hook, function handleCors (req, reply, next) {
|
||||
const ret = optionsResolver(req)
|
||||
if (ret && typeof ret.then === 'function') {
|
||||
ret.then(options => addCorsHeadersHandler(fastify, normalizeCorsOptions(options, true), req, reply, next)).catch(next)
|
||||
return
|
||||
}
|
||||
next(new Error('Invalid CORS origin option'))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleCorsOptionsCallbackDelegator (optionsResolver, fastify, req, reply, next) {
|
||||
optionsResolver(req, (err, options) => {
|
||||
if (err) {
|
||||
next(err)
|
||||
} else {
|
||||
addCorsHeadersHandler(fastify, normalizeCorsOptions(options, true), req, reply, next)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('./types').FastifyCorsOptions} opts
|
||||
*/
|
||||
function normalizeCorsOptions (opts, dynamic) {
|
||||
const corsOptions = { ...defaultOptions, ...opts }
|
||||
if (Array.isArray(opts.origin) && opts.origin.indexOf('*') !== -1) {
|
||||
corsOptions.origin = '*'
|
||||
}
|
||||
if (Number.isInteger(corsOptions.cacheControl)) {
|
||||
// integer numbers are formatted this way
|
||||
corsOptions.cacheControl = `max-age=${corsOptions.cacheControl}`
|
||||
} else if (typeof corsOptions.cacheControl !== 'string') {
|
||||
// strings are applied directly and any other value is ignored
|
||||
corsOptions.cacheControl = null
|
||||
}
|
||||
corsOptions.dynamic = dynamic || false
|
||||
return corsOptions
|
||||
}
|
||||
|
||||
function addCorsHeadersHandler (fastify, options, req, reply, next) {
|
||||
if ((typeof options.origin !== 'string' && options.origin !== false) || options.dynamic) {
|
||||
// Always set Vary header for non-static origin option
|
||||
// https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches
|
||||
addOriginToVaryHeader(reply)
|
||||
}
|
||||
|
||||
const resolveOriginOption = typeof options.origin === 'function' ? resolveOriginWrapper(fastify, options.origin) : (_, cb) => cb(null, options.origin)
|
||||
|
||||
resolveOriginOption(req, (error, resolvedOriginOption) => {
|
||||
if (error !== null) {
|
||||
return next(error)
|
||||
}
|
||||
|
||||
// Disable CORS and preflight if false
|
||||
if (resolvedOriginOption === false) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// Falsy values are invalid
|
||||
if (!resolvedOriginOption) {
|
||||
return next(new Error('Invalid CORS origin option'))
|
||||
}
|
||||
|
||||
addCorsHeaders(req, reply, resolvedOriginOption, options)
|
||||
|
||||
if (req.raw.method === 'OPTIONS' && options.preflight === true) {
|
||||
// Strict mode enforces the required headers for preflight
|
||||
if (options.strictPreflight === true && (!req.headers.origin || !req.headers['access-control-request-method'])) {
|
||||
reply.status(400).type('text/plain').send('Invalid Preflight Request')
|
||||
return
|
||||
}
|
||||
|
||||
req.corsPreflightEnabled = true
|
||||
|
||||
addPreflightHeaders(req, reply, options)
|
||||
|
||||
if (!options.preflightContinue) {
|
||||
// Do not call the hook callback and terminate the request
|
||||
// Safari (and potentially other browsers) need content-length 0,
|
||||
// for 204 or they just hang waiting for a body
|
||||
reply
|
||||
.code(options.optionsSuccessStatus)
|
||||
.header('Content-Length', '0')
|
||||
.send()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return next()
|
||||
})
|
||||
}
|
||||
|
||||
function addCorsHeaders (req, reply, originOption, corsOptions) {
|
||||
const origin = getAccessControlAllowOriginHeader(req.headers.origin, originOption)
|
||||
// In the case of origin not allowed the header is not
|
||||
// written in the response.
|
||||
// https://github.com/fastify/fastify-cors/issues/127
|
||||
if (origin) {
|
||||
reply.header('Access-Control-Allow-Origin', origin)
|
||||
}
|
||||
|
||||
if (corsOptions.credentials) {
|
||||
reply.header('Access-Control-Allow-Credentials', 'true')
|
||||
}
|
||||
|
||||
if (corsOptions.exposedHeaders !== null) {
|
||||
reply.header(
|
||||
'Access-Control-Expose-Headers',
|
||||
Array.isArray(corsOptions.exposedHeaders) ? corsOptions.exposedHeaders.join(', ') : corsOptions.exposedHeaders
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function addPreflightHeaders (req, reply, corsOptions) {
|
||||
reply.header(
|
||||
'Access-Control-Allow-Methods',
|
||||
Array.isArray(corsOptions.methods) ? corsOptions.methods.join(', ') : corsOptions.methods
|
||||
)
|
||||
|
||||
if (corsOptions.allowedHeaders === null) {
|
||||
addAccessControlRequestHeadersToVaryHeader(reply)
|
||||
const reqAllowedHeaders = req.headers['access-control-request-headers']
|
||||
if (reqAllowedHeaders !== undefined) {
|
||||
reply.header('Access-Control-Allow-Headers', reqAllowedHeaders)
|
||||
}
|
||||
} else {
|
||||
reply.header(
|
||||
'Access-Control-Allow-Headers',
|
||||
Array.isArray(corsOptions.allowedHeaders) ? corsOptions.allowedHeaders.join(', ') : corsOptions.allowedHeaders
|
||||
)
|
||||
}
|
||||
|
||||
if (corsOptions.maxAge !== null) {
|
||||
reply.header('Access-Control-Max-Age', String(corsOptions.maxAge))
|
||||
}
|
||||
|
||||
if (corsOptions.cacheControl) {
|
||||
reply.header('Cache-Control', corsOptions.cacheControl)
|
||||
}
|
||||
}
|
||||
|
||||
function resolveOriginWrapper (fastify, origin) {
|
||||
return function (req, cb) {
|
||||
const result = origin.call(fastify, req.headers.origin, cb)
|
||||
|
||||
// Allow for promises
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(res => cb(null, res), cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAccessControlAllowOriginHeader (reqOrigin, originOption) {
|
||||
if (typeof originOption === 'string') {
|
||||
// fixed or any origin ('*')
|
||||
return originOption
|
||||
}
|
||||
|
||||
// reflect origin
|
||||
return isRequestOriginAllowed(reqOrigin, originOption) ? reqOrigin : false
|
||||
}
|
||||
|
||||
function isRequestOriginAllowed (reqOrigin, allowedOrigin) {
|
||||
if (Array.isArray(allowedOrigin)) {
|
||||
for (let i = 0; i < allowedOrigin.length; ++i) {
|
||||
if (isRequestOriginAllowed(reqOrigin, allowedOrigin[i])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
} else if (typeof allowedOrigin === 'string') {
|
||||
return reqOrigin === allowedOrigin
|
||||
} else if (allowedOrigin instanceof RegExp) {
|
||||
allowedOrigin.lastIndex = 0
|
||||
return allowedOrigin.test(reqOrigin)
|
||||
} else {
|
||||
return !!allowedOrigin
|
||||
}
|
||||
}
|
||||
|
||||
const _fastifyCors = fp(fastifyCors, {
|
||||
fastify: '4.x',
|
||||
name: '@fastify/cors'
|
||||
})
|
||||
|
||||
/**
|
||||
* These export configurations enable JS and TS developers
|
||||
* to consumer fastify in whatever way best suits their needs.
|
||||
*/
|
||||
module.exports = _fastifyCors
|
||||
module.exports.fastifyCors = _fastifyCors
|
||||
module.exports.default = _fastifyCors
|
||||
59
backend/node_modules/@fastify/cors/package.json
generated
vendored
Normal file
59
backend/node_modules/@fastify/cors/package.json
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "@fastify/cors",
|
||||
"version": "9.0.1",
|
||||
"description": "Fastify CORS",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"types": "types/index.d.ts",
|
||||
"scripts": {
|
||||
"coverage": "tap --cov --coverage-report=html test",
|
||||
"lint": "standard",
|
||||
"lint:fix": "standard --fix",
|
||||
"test": "npm run test:unit && npm run test:typescript",
|
||||
"test:typescript": "tsd",
|
||||
"test:unit": "tap test/*.test.js"
|
||||
},
|
||||
"keywords": [
|
||||
"fastify",
|
||||
"cors",
|
||||
"headers",
|
||||
"access",
|
||||
"control"
|
||||
],
|
||||
"author": "Tomas Della Vedova - @delvedor (http://delved.org)",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/fastify-cors.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/fastify-cors/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/fastify-cors#readme",
|
||||
"devDependencies": {
|
||||
"@fastify/pre-commit": "^2.0.2",
|
||||
"@types/node": "^20.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.4.1",
|
||||
"@typescript-eslint/parser": "^6.4.0",
|
||||
"cors": "^2.8.5",
|
||||
"fastify": "^4.0.0-rc.2",
|
||||
"standard": "^17.0.0",
|
||||
"tap": "16.3.9",
|
||||
"tsd": "^0.30.0",
|
||||
"typescript": "^5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"fastify-plugin": "^4.0.0",
|
||||
"mnemonist": "0.39.6"
|
||||
},
|
||||
"tsd": {
|
||||
"directory": "test"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
941
backend/node_modules/@fastify/cors/test/cors.test.js
generated
vendored
Normal file
941
backend/node_modules/@fastify/cors/test/cors.test.js
generated
vendored
Normal file
@@ -0,0 +1,941 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const { createReadStream, statSync, readFileSync } = require('node:fs')
|
||||
const Fastify = require('fastify')
|
||||
const cors = require('../')
|
||||
const { resolve } = require('node:path')
|
||||
|
||||
test('Should add cors headers', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should add cors headers when payload is a stream', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors)
|
||||
const filePath = resolve(__dirname, __filename)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const stream = createReadStream(filePath)
|
||||
reply
|
||||
.type('application/json')
|
||||
.header('Content-Length', statSync(filePath).size)
|
||||
.send(stream)
|
||||
})
|
||||
|
||||
const fileContent = readFileSync(filePath, 'utf-8')
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, fileContent)
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'content-length': statSync(filePath).size
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should add cors headers (custom values)', t => {
|
||||
t.plan(10)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, {
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123,
|
||||
cacheControl: 321
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, woo',
|
||||
'access-control-max-age': '123',
|
||||
'cache-control': 'max-age=321',
|
||||
'content-length': '0'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support dynamic config (callback)', t => {
|
||||
t.plan(16)
|
||||
|
||||
const configs = [{
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123,
|
||||
cacheControl: 456
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321,
|
||||
cacheControl: '456'
|
||||
}]
|
||||
|
||||
const fastify = Fastify()
|
||||
let requestId = 0
|
||||
const configDelegation = function (req, cb) {
|
||||
// request should have id
|
||||
t.ok(req.id)
|
||||
// request should not have send
|
||||
t.notOk(req.send)
|
||||
const config = configs[requestId]
|
||||
requestId++
|
||||
if (config) {
|
||||
cb(null, config)
|
||||
} else {
|
||||
cb(new Error('ouch'))
|
||||
}
|
||||
}
|
||||
fastify.register(cors, () => configDelegation)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'cache-control': '456',
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support dynamic config (Promise)', t => {
|
||||
t.plan(23)
|
||||
|
||||
const configs = [{
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123,
|
||||
cacheControl: 456
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321,
|
||||
cacheControl: true // Invalid value should be ignored
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321,
|
||||
cacheControl: 'public, max-age=456'
|
||||
}]
|
||||
|
||||
const fastify = Fastify()
|
||||
let requestId = 0
|
||||
const configDelegation = function (req) {
|
||||
// request should have id
|
||||
t.ok(req.id)
|
||||
// request should not have send
|
||||
t.notOk(req.send)
|
||||
const config = configs[requestId]
|
||||
requestId++
|
||||
if (config) {
|
||||
return Promise.resolve(config)
|
||||
} else {
|
||||
return Promise.reject(new Error('ouch'))
|
||||
}
|
||||
}
|
||||
fastify.register(cors, () => configDelegation)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'sample.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
t.equal(res.headers['cache-control'], undefined, 'cache-control omitted (invalid value)')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'cache-control': 'public, max-age=456', // cache-control included (custom string)
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support dynamic config. (Invalid function)', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, () => (a, b, c) => {})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Dynamic origin resolution (valid origin)', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
const origin = function (header, cb) {
|
||||
t.equal(header, 'example.com')
|
||||
t.same(this, fastify)
|
||||
cb(null, true)
|
||||
}
|
||||
fastify.register(cors, { origin })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Dynamic origin resolution (not valid origin)', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
const origin = (header, cb) => {
|
||||
t.equal(header, 'example.com')
|
||||
cb(null, false)
|
||||
}
|
||||
fastify.register(cors, { origin })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.same(res.headers, {
|
||||
'content-length': '2',
|
||||
'content-type': 'text/plain; charset=utf-8',
|
||||
connection: 'keep-alive',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Dynamic origin resolution (errored)', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
const origin = (header, cb) => {
|
||||
t.equal(header, 'example.com')
|
||||
cb(new Error('ouch'))
|
||||
}
|
||||
fastify.register(cors, { origin })
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Dynamic origin resolution (invalid result)', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
const origin = (header, cb) => {
|
||||
t.equal(header, 'example.com')
|
||||
cb(null, undefined)
|
||||
}
|
||||
fastify.register(cors, { origin })
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Dynamic origin resolution (valid origin - promises)', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
const origin = (header, cb) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
t.equal(header, 'example.com')
|
||||
resolve(true)
|
||||
})
|
||||
}
|
||||
fastify.register(cors, { origin })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Dynamic origin resolution (not valid origin - promises)', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
const origin = (header, cb) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
t.equal(header, 'example.com')
|
||||
resolve(false)
|
||||
})
|
||||
}
|
||||
fastify.register(cors, { origin })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.same(res.headers, {
|
||||
'content-length': '2',
|
||||
'content-type': 'text/plain; charset=utf-8',
|
||||
connection: 'keep-alive',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Dynamic origin resolution (errored - promises)', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
const origin = (header, cb) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
t.equal(header, 'example.com')
|
||||
reject(new Error('ouch'))
|
||||
})
|
||||
}
|
||||
fastify.register(cors, { origin })
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should reply 404 without cors headers when origin is false', t => {
|
||||
t.plan(8)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, {
|
||||
origin: false,
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 404)
|
||||
t.equal(res.payload, '{"message":"Route OPTIONS:/ not found","error":"Not Found","statusCode":404}')
|
||||
t.same(res.headers, {
|
||||
'content-length': '76',
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
connection: 'keep-alive'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.same(res.headers, {
|
||||
'content-length': '2',
|
||||
'content-type': 'text/plain; charset=utf-8',
|
||||
connection: 'keep-alive'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Server error if origin option is falsy but not false', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { origin: '' })
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 500)
|
||||
t.same(res.json(), { statusCode: 500, error: 'Internal Server Error', message: 'Invalid CORS origin option' })
|
||||
t.same(res.headers, {
|
||||
'content-length': '89',
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
connection: 'keep-alive'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Allow only request from a specific origin', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { origin: 'other.io' })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'example.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'other.io'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
})
|
||||
|
||||
test('Allow only request from multiple specific origin', t => {
|
||||
t.plan(9)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { origin: ['other.io', 'example.com'] })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'other.io' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'other.io',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'foo.com' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
vary: 'Origin'
|
||||
})
|
||||
t.equal(res.headers['access-control-allow-origin'], undefined)
|
||||
})
|
||||
})
|
||||
|
||||
test('Allow only request from a specific origin using regex', t => {
|
||||
t.plan(8)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { origin: /(?:example|other)\.com/giu })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
// .test was previously used, which caused 2 consecutive requests to return
|
||||
// different results with global (e.g. /g) regexes. Therefore, check this
|
||||
// twice to check consistency
|
||||
for (let i = 0; i < 2; i++) {
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { origin: 'https://www.example.com/' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'https://www.example.com/',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('Disable preflight', t => {
|
||||
t.plan(7)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { preflight: false })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/hello'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 404)
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should always add vary header to `Origin` for reflected origin', t => {
|
||||
t.plan(12)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { origin: true })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
// Invalid Preflight
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 400)
|
||||
t.equal(res.payload, 'Invalid Preflight Request')
|
||||
t.match(res.headers, {
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
// Valid Preflight
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
// Other Route
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should always add vary header to `Origin` for reflected origin (vary is array)', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
// Mock getHeader function
|
||||
fastify.decorateReply('getHeader', (name) => ['foo', 'bar'])
|
||||
|
||||
fastify.register(cors, { origin: true })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
vary: 'foo, bar, Origin'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Allow only request from with specific headers', t => {
|
||||
t.plan(8)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, {
|
||||
allowedHeaders: 'foo',
|
||||
exposedHeaders: 'bar'
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-headers': 'foo'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-expose-headers': 'bar'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support wildcard config /1', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { origin: '*' })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.equal(res.headers['access-control-allow-origin'], '*')
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support wildcard config /2', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { origin: ['*'] })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.equal(res.headers['access-control-allow-origin'], '*')
|
||||
})
|
||||
})
|
||||
706
backend/node_modules/@fastify/cors/test/hooks.test.js
generated
vendored
Normal file
706
backend/node_modules/@fastify/cors/test/hooks.test.js
generated
vendored
Normal file
@@ -0,0 +1,706 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const Fastify = require('fastify')
|
||||
const kFastifyContext = require('fastify/lib/symbols').kRouteContext
|
||||
const cors = require('..')
|
||||
|
||||
test('Should error on invalid hook option', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.rejects(fastify.register(cors, { hook: 'invalid' }), new TypeError('@fastify/cors: Invalid hook option provided.'))
|
||||
})
|
||||
|
||||
test('Should set hook onRequest if hook option is not set', async (t) => {
|
||||
t.plan(10)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors)
|
||||
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.equal(request[kFastifyContext].onError, null)
|
||||
t.equal(request[kFastifyContext].onRequest.length, 1)
|
||||
t.equal(request[kFastifyContext].onSend, null)
|
||||
t.equal(request[kFastifyContext].preHandler, null)
|
||||
t.equal(request[kFastifyContext].preParsing, null)
|
||||
t.equal(request[kFastifyContext].preSerialization, null)
|
||||
t.equal(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should set hook onRequest if hook option is set to onRequest', async (t) => {
|
||||
t.plan(10)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'onRequest'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.equal(request[kFastifyContext].onError, null)
|
||||
t.equal(request[kFastifyContext].onRequest.length, 1)
|
||||
t.equal(request[kFastifyContext].onSend, null)
|
||||
t.equal(request[kFastifyContext].preHandler, null)
|
||||
t.equal(request[kFastifyContext].preParsing, null)
|
||||
t.equal(request[kFastifyContext].preSerialization, null)
|
||||
t.equal(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should set hook preParsing if hook option is set to preParsing', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preParsing'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.equal(request[kFastifyContext].onError, null)
|
||||
t.equal(request[kFastifyContext].onRequest, null)
|
||||
t.equal(request[kFastifyContext].onSend, null)
|
||||
t.equal(request[kFastifyContext].preHandler, null)
|
||||
t.equal(request[kFastifyContext].preParsing.length, 1)
|
||||
t.equal(request[kFastifyContext].preSerialization, null)
|
||||
t.equal(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
|
||||
test('Should set hook preValidation if hook option is set to preValidation', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preValidation'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.equal(request[kFastifyContext].onError, null)
|
||||
t.equal(request[kFastifyContext].onRequest, null)
|
||||
t.equal(request[kFastifyContext].onSend, null)
|
||||
t.equal(request[kFastifyContext].preHandler, null)
|
||||
t.equal(request[kFastifyContext].preParsing, null)
|
||||
t.equal(request[kFastifyContext].preSerialization, null)
|
||||
t.equal(request[kFastifyContext].preValidation.length, 1)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
|
||||
test('Should set hook preParsing if hook option is set to preParsing', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preParsing'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.equal(request[kFastifyContext].onError, null)
|
||||
t.equal(request[kFastifyContext].onRequest, null)
|
||||
t.equal(request[kFastifyContext].onSend, null)
|
||||
t.equal(request[kFastifyContext].preHandler, null)
|
||||
t.equal(request[kFastifyContext].preParsing.length, 1)
|
||||
t.equal(request[kFastifyContext].preSerialization, null)
|
||||
t.equal(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
|
||||
test('Should set hook preHandler if hook option is set to preHandler', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preHandler'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.equal(request[kFastifyContext].onError, null)
|
||||
t.equal(request[kFastifyContext].onRequest, null)
|
||||
t.equal(request[kFastifyContext].onSend, null)
|
||||
t.equal(request[kFastifyContext].preHandler.length, 1)
|
||||
t.equal(request[kFastifyContext].preParsing, null)
|
||||
t.equal(request[kFastifyContext].preSerialization, null)
|
||||
t.equal(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
|
||||
test('Should set hook onSend if hook option is set to onSend', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'onSend'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.equal(request[kFastifyContext].onError, null)
|
||||
t.equal(request[kFastifyContext].onRequest, null)
|
||||
t.equal(request[kFastifyContext].onSend.length, 1)
|
||||
t.equal(request[kFastifyContext].preHandler, null)
|
||||
t.equal(request[kFastifyContext].preParsing, null)
|
||||
t.equal(request[kFastifyContext].preSerialization, null)
|
||||
t.equal(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
|
||||
test('Should set hook preSerialization if hook option is set to preSerialization', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preSerialization'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.equal(request[kFastifyContext].onError, null)
|
||||
t.equal(request[kFastifyContext].onRequest, null)
|
||||
t.equal(request[kFastifyContext].onSend, null)
|
||||
t.equal(request[kFastifyContext].preHandler, null)
|
||||
t.equal(request[kFastifyContext].preParsing, null)
|
||||
t.equal(request[kFastifyContext].preSerialization.length, 1)
|
||||
t.equal(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ nonString: true })
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, '{"nonString":true}')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config', t => {
|
||||
t.plan(16)
|
||||
|
||||
const configs = [{
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321
|
||||
}]
|
||||
|
||||
const fastify = Fastify()
|
||||
let requestId = 0
|
||||
const configDelegation = function (req, cb) {
|
||||
// request should have id
|
||||
t.ok(req.id)
|
||||
// request should not have send
|
||||
t.notOk(req.send)
|
||||
const config = configs[requestId]
|
||||
requestId++
|
||||
if (config) {
|
||||
cb(null, config)
|
||||
} else {
|
||||
cb(new Error('ouch'))
|
||||
}
|
||||
}
|
||||
fastify.register(cors, {
|
||||
hook: 'preHandler',
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config (callback)', t => {
|
||||
t.plan(16)
|
||||
|
||||
const configs = [{
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321
|
||||
}]
|
||||
|
||||
const fastify = Fastify()
|
||||
let requestId = 0
|
||||
const configDelegation = function (req, cb) {
|
||||
// request should have id
|
||||
t.ok(req.id)
|
||||
// request should not have send
|
||||
t.notOk(req.send)
|
||||
const config = configs[requestId]
|
||||
requestId++
|
||||
if (config) {
|
||||
cb(null, config)
|
||||
} else {
|
||||
cb(new Error('ouch'))
|
||||
}
|
||||
}
|
||||
fastify.register(cors, {
|
||||
hook: 'preParsing',
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config (Promise)', t => {
|
||||
t.plan(16)
|
||||
|
||||
const configs = [{
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321
|
||||
}]
|
||||
|
||||
const fastify = Fastify()
|
||||
let requestId = 0
|
||||
const configDelegation = function (req) {
|
||||
// request should have id
|
||||
t.ok(req.id)
|
||||
// request should not have send
|
||||
t.notOk(req.send)
|
||||
const config = configs[requestId]
|
||||
requestId++
|
||||
if (config) {
|
||||
return Promise.resolve(config)
|
||||
} else {
|
||||
return Promise.reject(new Error('ouch'))
|
||||
}
|
||||
}
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preParsing',
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config (Promise), but should error /1', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
const configDelegation = function () {
|
||||
return false
|
||||
}
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preParsing',
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 500)
|
||||
t.equal(res.payload, '{"statusCode":500,"error":"Internal Server Error","message":"Invalid CORS origin option"}')
|
||||
t.match(res.headers, {
|
||||
'content-length': '89'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config (Promise), but should error /2', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
const configDelegation = function () {
|
||||
return false
|
||||
}
|
||||
|
||||
fastify.register(cors, {
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 500)
|
||||
t.equal(res.payload, '{"statusCode":500,"error":"Internal Server Error","message":"Invalid CORS origin option"}')
|
||||
t.match(res.headers, {
|
||||
'content-length': '89'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
435
backend/node_modules/@fastify/cors/test/preflight.test.js
generated
vendored
Normal file
435
backend/node_modules/@fastify/cors/test/preflight.test.js
generated
vendored
Normal file
@@ -0,0 +1,435 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const Fastify = require('fastify')
|
||||
const cors = require('../')
|
||||
|
||||
test('Should reply to preflight requests', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors)
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should add access-control-allow-headers to response if preflight req has access-control-request-headers', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors)
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-headers': 'x-requested-with',
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
'access-control-allow-headers': 'x-requested-with',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should reply to preflight requests with custom status code', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { optionsSuccessStatus: 200 })
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should be able to override preflight response with a route', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { preflightContinue: true })
|
||||
|
||||
fastify.options('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
// Only the base cors headers and no preflight headers
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
})
|
||||
|
||||
test('Should reply to all options requests', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors)
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/hello',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support a prefix for preflight requests', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register((instance, opts, next) => {
|
||||
instance.register(cors)
|
||||
next()
|
||||
}, { prefix: '/subsystem' })
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/hello'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 404)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/subsystem/hello',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('hide options route by default', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onRoute', (route) => {
|
||||
if (route.method === 'OPTIONS' && route.url === '*') {
|
||||
t.equal(route.schema.hide, true)
|
||||
}
|
||||
})
|
||||
fastify.register(cors)
|
||||
|
||||
fastify.ready(err => {
|
||||
t.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
test('show options route', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onRoute', (route) => {
|
||||
if (route.method === 'OPTIONS' && route.url === '*') {
|
||||
t.equal(route.schema.hide, false)
|
||||
}
|
||||
})
|
||||
fastify.register(cors, { hideOptionsRoute: false })
|
||||
|
||||
fastify.ready(err => {
|
||||
t.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
test('Allow only request from with specific methods', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { methods: ['GET', 'POST'] })
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-methods': 'GET, POST'
|
||||
})
|
||||
t.notMatch(res.headers, { vary: 'Origin' })
|
||||
})
|
||||
})
|
||||
|
||||
test('Should reply with 400 error to OPTIONS requests missing origin header when default strictPreflight', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors)
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.equal(res.payload, 'Invalid Preflight Request')
|
||||
})
|
||||
})
|
||||
|
||||
test('Should reply with 400 to OPTIONS requests when missing Access-Control-Request-Method header when default strictPreflight', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, {
|
||||
strictPreflight: true
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.equal(res.payload, 'Invalid Preflight Request')
|
||||
})
|
||||
})
|
||||
|
||||
test('Should reply to all preflight requests when strictPreflight is disabled', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { strictPreflight: false })
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/'
|
||||
// No access-control-request-method or origin headers
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Default empty 200 response with preflightContinue on OPTIONS routes', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { preflightContinue: true })
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/doesnotexist',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Can override preflight response with preflightContinue', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(cors, { preflightContinue: true })
|
||||
|
||||
fastify.options('/', (req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'ok')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support ongoing prefix ', t => {
|
||||
t.plan(12)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(async (instance) => {
|
||||
instance.register(cors)
|
||||
}, { prefix: '/prefix' })
|
||||
|
||||
// support prefixed route
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/prefix',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
// support prefixed route without / continue
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/prefixfoo',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
// support prefixed route with / continue
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/prefix/foo',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
delete res.headers.date
|
||||
t.equal(res.statusCode, 204)
|
||||
t.equal(res.payload, '')
|
||||
t.match(res.headers, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
})
|
||||
229
backend/node_modules/@fastify/cors/test/vary.test.js
generated
vendored
Normal file
229
backend/node_modules/@fastify/cors/test/vary.test.js
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tap').test
|
||||
const createAddFieldnameToVary = require('../vary').createAddFieldnameToVary
|
||||
const parse = require('../vary').parse
|
||||
|
||||
test('Should set * even if we set a specific field', t => {
|
||||
t.plan(1)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return '*'
|
||||
},
|
||||
header (name, value) {
|
||||
t.fail('Should not be here')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('Should set * even if we set a specific field', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addWildcardToVary = createAddFieldnameToVary('*')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return 'Origin'
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, '*')
|
||||
}
|
||||
}
|
||||
|
||||
addWildcardToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should set * when field contains a *', t => {
|
||||
t.plan(3)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return ['Origin', '*', 'Access-Control-Request-Headers']
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, '*')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('Should concat vary values', t => {
|
||||
t.plan(3)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return 'Access-Control-Request-Headers'
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, 'Access-Control-Request-Headers, Origin')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('Should concat vary values ignoring consecutive commas', t => {
|
||||
t.plan(3)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return ' Access-Control-Request-Headers,Access-Control-Request-Method'
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, ' Access-Control-Request-Headers,Access-Control-Request-Method, Origin')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('Should concat vary values ignoring whitespace', t => {
|
||||
t.plan(3)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return ' Access-Control-Request-Headers ,Access-Control-Request-Method'
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, ' Access-Control-Request-Headers ,Access-Control-Request-Method, Origin')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('Should set the field as value for vary if no vary is defined', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return undefined
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, 'Origin')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should set * as value for vary if vary contains *', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return 'Accept,*'
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, '*')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should set Accept-Encoding as value for vary if vary is empty string', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addAcceptEncodingToVary = createAddFieldnameToVary('Accept-Encoding')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return ''
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, 'Accept-Encoding')
|
||||
}
|
||||
}
|
||||
|
||||
addAcceptEncodingToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should have no issues with values containing dashes', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addXFooToVary = createAddFieldnameToVary('X-Foo')
|
||||
const replyMock = {
|
||||
value: 'Accept-Encoding',
|
||||
getHeader (name) {
|
||||
return this.value
|
||||
},
|
||||
header (name, value) {
|
||||
t.same(name, 'Vary')
|
||||
t.same(value, 'Accept-Encoding, X-Foo')
|
||||
this.value = value
|
||||
}
|
||||
}
|
||||
|
||||
addXFooToVary(replyMock)
|
||||
addXFooToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should ignore the header as value for vary if it is already in vary', t => {
|
||||
t.plan(1)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader (name) {
|
||||
return 'Origin'
|
||||
},
|
||||
header (name, value) {
|
||||
t.fail('Should not be here')
|
||||
}
|
||||
}
|
||||
addOriginToVary(replyMock)
|
||||
addOriginToVary(replyMock)
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('parse', t => {
|
||||
t.plan(18)
|
||||
t.same(parse(''), [])
|
||||
t.same(parse('a'), ['a'])
|
||||
t.same(parse('a,b'), ['a', 'b'])
|
||||
t.same(parse(' a,b'), ['a', 'b'])
|
||||
t.same(parse('a,b '), ['a', 'b'])
|
||||
t.same(parse('a,b,c'), ['a', 'b', 'c'])
|
||||
t.same(parse('A,b,c'), ['a', 'b', 'c'])
|
||||
t.same(parse('a,b,c,'), ['a', 'b', 'c'])
|
||||
t.same(parse('a,b,c, '), ['a', 'b', 'c'])
|
||||
t.same(parse(',a,b,c'), ['a', 'b', 'c'])
|
||||
t.same(parse(' ,a,b,c'), ['a', 'b', 'c'])
|
||||
t.same(parse('a,,b,c'), ['a', 'b', 'c'])
|
||||
t.same(parse('a,,,b,,c'), ['a', 'b', 'c'])
|
||||
t.same(parse('a, b,c'), ['a', 'b', 'c'])
|
||||
t.same(parse('a, b,c'), ['a', 'b', 'c'])
|
||||
t.same(parse('a, , b,c'), ['a', 'b', 'c'])
|
||||
t.same(parse('a, , b,c'), ['a', 'b', 'c'])
|
||||
|
||||
// one for the cache
|
||||
t.same(parse('A,b,c'), ['a', 'b', 'c'])
|
||||
})
|
||||
|
||||
test('createAddFieldnameToVary', t => {
|
||||
t.plan(2)
|
||||
t.same(typeof createAddFieldnameToVary('valid-header'), 'function')
|
||||
t.throws(() => createAddFieldnameToVary('invalid:header'), TypeError, 'Field contains invalid characters.')
|
||||
})
|
||||
116
backend/node_modules/@fastify/cors/types/index.d.ts
generated
vendored
Normal file
116
backend/node_modules/@fastify/cors/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import { FastifyInstance, FastifyPluginCallback, FastifyRequest } from 'fastify';
|
||||
|
||||
type OriginCallback = (err: Error | null, origin: ValueOrArray<OriginType>) => void;
|
||||
type OriginType = string | boolean | RegExp;
|
||||
type ValueOrArray<T> = T | ArrayOfValueOrArray<T>;
|
||||
|
||||
interface ArrayOfValueOrArray<T> extends Array<ValueOrArray<T>> {
|
||||
}
|
||||
|
||||
type FastifyCorsPlugin = FastifyPluginCallback<
|
||||
NonNullable<fastifyCors.FastifyCorsOptions> | fastifyCors.FastifyCorsOptionsDelegate
|
||||
>;
|
||||
|
||||
type FastifyCorsHook =
|
||||
| 'onRequest'
|
||||
| 'preParsing'
|
||||
| 'preValidation'
|
||||
| 'preHandler'
|
||||
| 'preSerialization'
|
||||
| 'onSend'
|
||||
|
||||
declare namespace fastifyCors {
|
||||
export type OriginFunction = (origin: string | undefined, callback: OriginCallback) => void;
|
||||
|
||||
export interface FastifyCorsOptions {
|
||||
/**
|
||||
* Configures the Lifecycle Hook.
|
||||
*/
|
||||
hook?: FastifyCorsHook;
|
||||
|
||||
/**
|
||||
* Configures the delegate function.
|
||||
*/
|
||||
delegator?: FastifyCorsOptionsDelegate;
|
||||
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Origin CORS header.
|
||||
*/
|
||||
origin?: ValueOrArray<OriginType> | fastifyCors.OriginFunction;
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Credentials CORS header.
|
||||
* Set to true to pass the header, otherwise it is omitted.
|
||||
*/
|
||||
credentials?: boolean;
|
||||
/**
|
||||
* Configures the Access-Control-Expose-Headers CORS header.
|
||||
* Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range')
|
||||
* or an array (ex: ['Content-Range', 'X-Content-Range']).
|
||||
* If not specified, no custom headers are exposed.
|
||||
*/
|
||||
exposedHeaders?: string | string[];
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Headers CORS header.
|
||||
* Expects a comma-delimited string (ex: 'Content-Type,Authorization')
|
||||
* or an array (ex: ['Content-Type', 'Authorization']). If not
|
||||
* specified, defaults to reflecting the headers specified in the
|
||||
* request's Access-Control-Request-Headers header.
|
||||
*/
|
||||
allowedHeaders?: string | string[];
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Methods CORS header.
|
||||
* Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: ['GET', 'PUT', 'POST']).
|
||||
*/
|
||||
methods?: string | string[];
|
||||
/**
|
||||
* Configures the Access-Control-Max-Age CORS header.
|
||||
* Set to an integer to pass the header, otherwise it is omitted.
|
||||
*/
|
||||
maxAge?: number;
|
||||
/**
|
||||
* Configures the Cache-Control header for CORS preflight responses.
|
||||
* Set to an integer to pass the header as `Cache-Control: max-age=${cacheControl}`,
|
||||
* or set to a string to pass the header as `Cache-Control: ${cacheControl}` (fully define
|
||||
* the header value), otherwise the header is omitted.
|
||||
*/
|
||||
cacheControl?: number | string;
|
||||
/**
|
||||
* Pass the CORS preflight response to the route handler (default: false).
|
||||
*/
|
||||
preflightContinue?: boolean;
|
||||
/**
|
||||
* Provides a status code to use for successful OPTIONS requests,
|
||||
* since some legacy browsers (IE11, various SmartTVs) choke on 204.
|
||||
*/
|
||||
optionsSuccessStatus?: number;
|
||||
/**
|
||||
* Pass the CORS preflight response to the route handler (default: false).
|
||||
*/
|
||||
preflight?: boolean;
|
||||
/**
|
||||
* Enforces strict requirement of the CORS preflight request headers (Access-Control-Request-Method and Origin).
|
||||
* Preflight requests without the required headers will result in 400 errors when set to `true` (default: `true`).
|
||||
*/
|
||||
strictPreflight?: boolean;
|
||||
/**
|
||||
* Hide options route from the documentation built using fastify-swagger (default: true).
|
||||
*/
|
||||
hideOptionsRoute?: boolean;
|
||||
}
|
||||
|
||||
export interface FastifyCorsOptionsDelegateCallback { (req: FastifyRequest, cb: (error: Error | null, corsOptions?: FastifyCorsOptions) => void): void }
|
||||
export interface FastifyCorsOptionsDelegatePromise { (req: FastifyRequest): Promise<FastifyCorsOptions> }
|
||||
export type FastifyCorsOptionsDelegate = FastifyCorsOptionsDelegateCallback | FastifyCorsOptionsDelegatePromise
|
||||
export type FastifyPluginOptionsDelegate<T = FastifyCorsOptionsDelegate> = (instance: FastifyInstance) => T;
|
||||
|
||||
export const fastifyCors: FastifyCorsPlugin
|
||||
export { fastifyCors as default };
|
||||
}
|
||||
|
||||
declare function fastifyCors(
|
||||
...params: Parameters<FastifyCorsPlugin>
|
||||
): ReturnType<FastifyCorsPlugin>;
|
||||
|
||||
export = fastifyCors;
|
||||
355
backend/node_modules/@fastify/cors/types/index.test-d.ts
generated
vendored
Normal file
355
backend/node_modules/@fastify/cors/types/index.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
import fastify, { FastifyRequest } from 'fastify'
|
||||
import { expectType } from 'tsd'
|
||||
import fastifyCors, {
|
||||
FastifyCorsOptions,
|
||||
FastifyCorsOptionsDelegate,
|
||||
FastifyCorsOptionsDelegatePromise,
|
||||
FastifyPluginOptionsDelegate,
|
||||
OriginFunction
|
||||
} from '..'
|
||||
|
||||
const app = fastify()
|
||||
|
||||
app.register(fastifyCors)
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: true,
|
||||
allowedHeaders: 'authorization,content-type',
|
||||
methods: 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
|
||||
credentials: true,
|
||||
exposedHeaders: 'authorization',
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: true,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 'public, max-age=3500',
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: '*',
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: /\*/,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: ['*', 'something'],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
const corsDelegate: OriginFunction = (origin, cb) => {
|
||||
if (origin === undefined || /localhost/.test(origin)) {
|
||||
cb(null, true)
|
||||
return
|
||||
}
|
||||
cb(new Error(), false)
|
||||
}
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: corsDelegate,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: (origin, cb) => cb(null, true)
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: (origin, cb) => cb(null, '*')
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: (origin, cb) => cb(null, /\*/)
|
||||
})
|
||||
|
||||
const appHttp2 = fastify({ http2: true })
|
||||
|
||||
appHttp2.register(fastifyCors)
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: true,
|
||||
allowedHeaders: 'authorization,content-type',
|
||||
methods: 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
|
||||
credentials: true,
|
||||
exposedHeaders: 'authorization',
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: true,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: '*',
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: /\*/,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: ['*', 'something'],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: (origin: string | undefined, cb: (err: Error | null, allow: boolean) => void) => {
|
||||
if (origin === undefined || /localhost/.test(origin)) {
|
||||
cb(null, true)
|
||||
return
|
||||
}
|
||||
cb(new Error(), false)
|
||||
},
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, (): FastifyCorsOptionsDelegate => (req, cb) => {
|
||||
cb(null, {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, (): FastifyCorsOptionsDelegatePromise => (req) => {
|
||||
return Promise.resolve({
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
})
|
||||
|
||||
const delegate: FastifyPluginOptionsDelegate<FastifyCorsOptionsDelegatePromise> = () => async (req) => {
|
||||
return {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
}
|
||||
}
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'onRequest'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preValidation'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preHandler'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preSerialization'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'onSend'
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing',
|
||||
delegator: (req, cb) => {
|
||||
if (req.url.startsWith('/some-value')) {
|
||||
cb(new Error())
|
||||
}
|
||||
cb(null, {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 12000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing',
|
||||
delegator: async (req: FastifyRequest): Promise<FastifyCorsOptions> => {
|
||||
return {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 'public, max-age=3500',
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, delegate)
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing',
|
||||
origin: function (origin) {
|
||||
expectType<string|undefined>(origin)
|
||||
},
|
||||
})
|
||||
116
backend/node_modules/@fastify/cors/vary.js
generated
vendored
Normal file
116
backend/node_modules/@fastify/cors/vary.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
'use strict'
|
||||
|
||||
const LRUCache = require('mnemonist/lru-cache')
|
||||
|
||||
/**
|
||||
* Field Value Components
|
||||
* Most HTTP header field values are defined using common syntax
|
||||
* components (token, quoted-string, and comment) separated by
|
||||
* whitespace or specific delimiting characters. Delimiters are chosen
|
||||
* from the set of US-ASCII visual characters not allowed in a token
|
||||
* (DQUOTE and "(),/:;<=>?@[\]{}").
|
||||
*
|
||||
* field-name = token
|
||||
* token = 1*tchar
|
||||
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
|
||||
* / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
|
||||
* / DIGIT / ALPHA
|
||||
* ; any VCHAR, except delimiters
|
||||
*
|
||||
* @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
|
||||
*/
|
||||
|
||||
const validFieldnameRE = /^[!#$%&'*+\-.^\w`|~]+$/u
|
||||
function validateFieldname (fieldname) {
|
||||
if (validFieldnameRE.test(fieldname) === false) {
|
||||
throw new TypeError('Fieldname contains invalid characters.')
|
||||
}
|
||||
}
|
||||
|
||||
function parse (header) {
|
||||
header = header.trim().toLowerCase()
|
||||
const result = []
|
||||
|
||||
if (header.length === 0) {
|
||||
// pass through
|
||||
} else if (header.indexOf(',') === -1) {
|
||||
result.push(header)
|
||||
} else {
|
||||
const il = header.length
|
||||
let i = 0
|
||||
let pos = 0
|
||||
let char
|
||||
|
||||
// tokenize the header
|
||||
for (i = 0; i < il; ++i) {
|
||||
char = header[i]
|
||||
// when we have whitespace set the pos to the next position
|
||||
if (char === ' ') {
|
||||
pos = i + 1
|
||||
// `,` is the separator of vary-values
|
||||
} else if (char === ',') {
|
||||
// if pos and current position are not the same we have a valid token
|
||||
if (pos !== i) {
|
||||
result.push(header.slice(pos, i))
|
||||
}
|
||||
// reset the positions
|
||||
pos = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
if (pos !== i) {
|
||||
result.push(header.slice(pos, i))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function createAddFieldnameToVary (fieldname) {
|
||||
const headerCache = new LRUCache(1000)
|
||||
|
||||
validateFieldname(fieldname)
|
||||
|
||||
return function (reply) {
|
||||
let header = reply.getHeader('Vary')
|
||||
|
||||
if (!header) {
|
||||
reply.header('Vary', fieldname)
|
||||
return
|
||||
}
|
||||
|
||||
if (header === '*') {
|
||||
return
|
||||
}
|
||||
|
||||
if (fieldname === '*') {
|
||||
reply.header('Vary', '*')
|
||||
return
|
||||
}
|
||||
|
||||
if (Array.isArray(header)) {
|
||||
header = header.join(', ')
|
||||
}
|
||||
|
||||
if (!headerCache.has(header)) {
|
||||
const vals = parse(header)
|
||||
|
||||
if (vals.indexOf('*') !== -1) {
|
||||
headerCache.set(header, '*')
|
||||
} else if (vals.indexOf(fieldname.toLowerCase()) === -1) {
|
||||
headerCache.set(header, header + ', ' + fieldname)
|
||||
} else {
|
||||
headerCache.set(header, null)
|
||||
}
|
||||
}
|
||||
const cached = headerCache.get(header)
|
||||
if (cached !== null) {
|
||||
reply.header('Vary', cached)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.createAddFieldnameToVary = createAddFieldnameToVary
|
||||
module.exports.addOriginToVaryHeader = createAddFieldnameToVary('Origin')
|
||||
module.exports.addAccessControlRequestHeadersToVaryHeader = createAddFieldnameToVary('Access-Control-Request-Headers')
|
||||
module.exports.parse = parse
|
||||
Reference in New Issue
Block a user