finalized project
This commit is contained in:
1 parent
b8b3e348e8
commit
4b87e9d20c
15 files changed
+1027
-4
No files matched your search
+86
@@ -0,0 +1,86 @@
|
||||
import type { CorsOptions, CorsOptionsDelegate } from "./types.ts";
|
||||
import { Cors } from "./cors.ts";
|
||||
|
||||
interface Req {
|
||||
method: string;
|
||||
headers: {
|
||||
get(headerKey: string): string | null | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
interface Res {
|
||||
status?: number | string;
|
||||
headers: {
|
||||
get(headerKey: string): string | null | undefined;
|
||||
set(headerKey: string, headerValue: string): any;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* abcCors middleware wrapper
|
||||
* @param o CorsOptions | CorsOptionsDelegate
|
||||
* @link https://github.com/tajpouria/cors/blob/master/README.md#cors
|
||||
*/
|
||||
export const abcCors = <
|
||||
RequestT extends Req = any,
|
||||
ResponseT extends Res = any,
|
||||
MiddlewareT extends (
|
||||
next: (...args: any) => any,
|
||||
) => (context: { request: RequestT; response: ResponseT }) => any = any,
|
||||
>(
|
||||
o?: CorsOptions | CorsOptionsDelegate<RequestT>,
|
||||
) => {
|
||||
const corsOptionsDelegate = Cors.produceCorsOptionsDelegate<
|
||||
CorsOptionsDelegate<RequestT>
|
||||
>(o);
|
||||
|
||||
return ((abcNext) =>
|
||||
async (context) => {
|
||||
const next = () => abcNext(context);
|
||||
|
||||
try {
|
||||
const { request, response } = context;
|
||||
|
||||
const options = await corsOptionsDelegate(request);
|
||||
|
||||
const corsOptions = Cors.produceCorsOptions(options || {});
|
||||
const originDelegate = Cors.produceOriginDelegate(corsOptions);
|
||||
|
||||
if (originDelegate) {
|
||||
const requestMethod = request.method;
|
||||
const getRequestHeader = (headerKey: string) =>
|
||||
request.headers.get(headerKey);
|
||||
const getResponseHeader = (headerKey: string) =>
|
||||
response.headers.get(headerKey);
|
||||
const setResponseHeader = (headerKey: string, headerValue: string) =>
|
||||
response.headers.set(headerKey, headerValue);
|
||||
const setStatus = (
|
||||
statusCode: number,
|
||||
) => (response.status = statusCode);
|
||||
const end = () => {};
|
||||
|
||||
const origin = await originDelegate(getRequestHeader("origin"));
|
||||
|
||||
if (!origin) return next();
|
||||
else {
|
||||
corsOptions.origin = origin;
|
||||
|
||||
return new Cors({
|
||||
corsOptions,
|
||||
requestMethod,
|
||||
getRequestHeader,
|
||||
getResponseHeader,
|
||||
setResponseHeader,
|
||||
setStatus,
|
||||
next,
|
||||
end,
|
||||
}).configureHeaders();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return next();
|
||||
}) as MiddlewareT;
|
||||
};
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
import type { CorsOptions, CorsOptionsDelegate } from "./types.ts";
|
||||
import { Cors } from "./cors.ts";
|
||||
|
||||
interface Req {
|
||||
method: string;
|
||||
headers: {
|
||||
get(headerKey: string): string | null | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
interface Res {
|
||||
status: (status: number) => any;
|
||||
headers: {
|
||||
get(headerKey: string): string | null | undefined;
|
||||
set(headerKey: string, headerValue: string): any;
|
||||
};
|
||||
send: (body: any) => any;
|
||||
end(...args: any): any;
|
||||
}
|
||||
|
||||
/**
|
||||
* attainCors middleware wrapper
|
||||
* @param o CorsOptions | CorsOptionsDelegate
|
||||
* @link https://github.com/tajpouria/cors/blob/master/README.md#cors
|
||||
*/
|
||||
export const attainCors = <
|
||||
RequestT extends Req = any,
|
||||
ResponseT extends Res = any,
|
||||
MiddlewareT extends (request: RequestT, response: ResponseT) => any = any,
|
||||
>(
|
||||
o?: CorsOptions | CorsOptionsDelegate<RequestT>,
|
||||
) => {
|
||||
const corsOptionsDelegate = Cors.produceCorsOptionsDelegate<
|
||||
CorsOptionsDelegate<RequestT>
|
||||
>(o);
|
||||
|
||||
return async function cors(request, response) {
|
||||
try {
|
||||
const fakeNext = () => undefined;
|
||||
const options = await corsOptionsDelegate(request);
|
||||
|
||||
const corsOptions = Cors.produceCorsOptions(options || {});
|
||||
const originDelegate = Cors.produceOriginDelegate(corsOptions);
|
||||
|
||||
if (originDelegate) {
|
||||
const requestMethod = request.method;
|
||||
const getRequestHeader = (headerKey: string) =>
|
||||
request.headers.get(headerKey);
|
||||
const getResponseHeader = (headerKey: string) =>
|
||||
response.headers.get(headerKey);
|
||||
const setResponseHeader = (headerKey: string, headerValue: string) =>
|
||||
response.headers.set(headerKey, headerValue);
|
||||
const setStatus = (statusCode: number) => response.status(statusCode);
|
||||
const end = response.end();
|
||||
|
||||
const origin = await originDelegate(getRequestHeader("origin"));
|
||||
|
||||
if (origin) {
|
||||
corsOptions.origin = origin;
|
||||
|
||||
new Cors({
|
||||
corsOptions,
|
||||
requestMethod,
|
||||
getRequestHeader,
|
||||
getResponseHeader,
|
||||
setResponseHeader,
|
||||
setStatus,
|
||||
next: fakeNext,
|
||||
end,
|
||||
}).configureHeaders();
|
||||
}
|
||||
}
|
||||
|
||||
if (request.method === "OPTIONS") {
|
||||
response.send("");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
} as MiddlewareT;
|
||||
};
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
import type {
|
||||
CorsOptions,
|
||||
CorsOptionsDelegate,
|
||||
OriginDelegate,
|
||||
} from "./types.ts";
|
||||
|
||||
interface DefaultCorsOptions {
|
||||
origin: string;
|
||||
methods: string;
|
||||
preflightContinue: boolean;
|
||||
optionsSuccessStatus: number;
|
||||
}
|
||||
|
||||
interface CorsProps {
|
||||
corsOptions: ReturnType<typeof Cors.produceCorsOptions>;
|
||||
requestMethod: string;
|
||||
getRequestHeader: (headerKey: string) => string | null | undefined;
|
||||
getResponseHeader: (headerKey: string) => string | null | undefined;
|
||||
setResponseHeader: (headerKey: string, headerValue: string) => any;
|
||||
setStatus: (statusCode: number) => any;
|
||||
next: (...args: any) => any;
|
||||
end: (...args: any) => any;
|
||||
}
|
||||
|
||||
export class Cors {
|
||||
constructor(private props: CorsProps) {}
|
||||
|
||||
public static produceCorsOptions = (
|
||||
corsOptions: CorsOptions = {},
|
||||
defaultCorsOptions: DefaultCorsOptions = {
|
||||
origin: "*",
|
||||
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 204,
|
||||
},
|
||||
) => ({
|
||||
...defaultCorsOptions,
|
||||
...corsOptions,
|
||||
});
|
||||
|
||||
public static produceCorsOptionsDelegate = <
|
||||
OptionsCallbackT = CorsOptionsDelegate<any>,
|
||||
>(
|
||||
o?: CorsOptions | OptionsCallbackT,
|
||||
) =>
|
||||
typeof o === "function"
|
||||
? (o as OptionsCallbackT)
|
||||
: ((((_request: any) => o) as unknown) as OptionsCallbackT);
|
||||
|
||||
public static produceOriginDelegate = (
|
||||
corsOptions: CorsProps["corsOptions"],
|
||||
) => {
|
||||
if (corsOptions.origin) {
|
||||
if (typeof corsOptions.origin === "function") {
|
||||
return corsOptions.origin as OriginDelegate;
|
||||
}
|
||||
|
||||
return ((_requestOrigin) => corsOptions.origin) as OriginDelegate;
|
||||
}
|
||||
};
|
||||
|
||||
public static isOriginAllowed = (
|
||||
requestOrigin: string | null | undefined,
|
||||
allowedOrigin: CorsOptions["origin"],
|
||||
): boolean => {
|
||||
if (Array.isArray(allowedOrigin)) {
|
||||
return allowedOrigin.some((ao) =>
|
||||
Cors.isOriginAllowed(requestOrigin, ao)
|
||||
);
|
||||
} else if (typeof allowedOrigin === "string") {
|
||||
return requestOrigin === allowedOrigin;
|
||||
} else if (
|
||||
allowedOrigin instanceof RegExp &&
|
||||
typeof requestOrigin === "string"
|
||||
) {
|
||||
return allowedOrigin.test(requestOrigin);
|
||||
} else return !!allowedOrigin;
|
||||
};
|
||||
|
||||
public configureHeaders = () => {
|
||||
const {
|
||||
props: {
|
||||
corsOptions,
|
||||
requestMethod,
|
||||
setResponseHeader,
|
||||
setStatus,
|
||||
next,
|
||||
end,
|
||||
},
|
||||
configureOrigin,
|
||||
} = this;
|
||||
|
||||
if (
|
||||
typeof requestMethod === "string" &&
|
||||
requestMethod.toUpperCase() === "OPTIONS"
|
||||
) {
|
||||
configureOrigin()
|
||||
.configureCredentials()
|
||||
.configureMethods()
|
||||
.configureAllowedHeaders()
|
||||
.configureMaxAge()
|
||||
.configureExposedHeaders();
|
||||
|
||||
if (corsOptions.preflightContinue) return next();
|
||||
else {
|
||||
setStatus(corsOptions.optionsSuccessStatus);
|
||||
setResponseHeader("Content-Length", "0");
|
||||
|
||||
return end();
|
||||
}
|
||||
} else {
|
||||
configureOrigin().configureCredentials().configureExposedHeaders();
|
||||
|
||||
return next();
|
||||
}
|
||||
};
|
||||
|
||||
private configureOrigin = () => {
|
||||
const {
|
||||
props: { corsOptions, getRequestHeader, setResponseHeader },
|
||||
setVaryHeader,
|
||||
} = this;
|
||||
|
||||
if (!corsOptions.origin || corsOptions.origin === "*") {
|
||||
setResponseHeader("Access-Control-Allow-Origin", "*");
|
||||
} else if (typeof corsOptions.origin === "string") {
|
||||
setResponseHeader("Access-Control-Allow-Origin", corsOptions.origin);
|
||||
setVaryHeader("Origin");
|
||||
} else {
|
||||
const requestOrigin = getRequestHeader("origin") ??
|
||||
getRequestHeader("Origin");
|
||||
|
||||
setResponseHeader(
|
||||
"Access-Control-Allow-Origin",
|
||||
Cors.isOriginAllowed(requestOrigin, corsOptions.origin)
|
||||
? (requestOrigin as string)
|
||||
: "false",
|
||||
);
|
||||
setVaryHeader("Origin");
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
private configureCredentials = () => {
|
||||
const { corsOptions, setResponseHeader } = this.props;
|
||||
|
||||
if (corsOptions.credentials === true) {
|
||||
setResponseHeader("Access-Control-Allow-Credentials", "true");
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
private configureMethods = () => {
|
||||
const { corsOptions, setResponseHeader } = this.props;
|
||||
|
||||
let methods = corsOptions.methods;
|
||||
|
||||
setResponseHeader(
|
||||
"Access-Control-Allow-Methods",
|
||||
Array.isArray(methods) ? methods.join(",") : methods,
|
||||
);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
private configureAllowedHeaders = () => {
|
||||
const {
|
||||
props: { corsOptions, getRequestHeader, setResponseHeader },
|
||||
setVaryHeader,
|
||||
} = this;
|
||||
|
||||
let allowedHeaders = corsOptions.allowedHeaders;
|
||||
|
||||
if (!allowedHeaders) {
|
||||
allowedHeaders = getRequestHeader("access-control-request-headers") ??
|
||||
getRequestHeader("Access-Control-Request-Headers") ??
|
||||
undefined;
|
||||
|
||||
setVaryHeader("Access-Control-request-Headers");
|
||||
}
|
||||
|
||||
if (allowedHeaders?.length) {
|
||||
setResponseHeader(
|
||||
"Access-Control-Allow-Headers",
|
||||
Array.isArray(allowedHeaders)
|
||||
? allowedHeaders.join(",")
|
||||
: allowedHeaders,
|
||||
);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
private configureMaxAge = () => {
|
||||
const { corsOptions, setResponseHeader } = this.props;
|
||||
|
||||
const maxAge = (typeof corsOptions.maxAge === "number" ||
|
||||
typeof corsOptions.maxAge === "string") &&
|
||||
corsOptions.maxAge.toString();
|
||||
|
||||
if (maxAge && maxAge.length) {
|
||||
setResponseHeader("Access-Control-Max-Age", maxAge);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
private configureExposedHeaders = () => {
|
||||
const { corsOptions, setResponseHeader } = this.props;
|
||||
|
||||
let exposedHeaders = corsOptions.exposedHeaders;
|
||||
|
||||
if (exposedHeaders?.length) {
|
||||
setResponseHeader(
|
||||
"Access-Control-Expose-Headers",
|
||||
Array.isArray(exposedHeaders)
|
||||
? exposedHeaders.join(",")
|
||||
: exposedHeaders,
|
||||
);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
private setVaryHeader = (field: string) => {
|
||||
const {
|
||||
props: { getResponseHeader, setResponseHeader },
|
||||
appendVaryHeader,
|
||||
} = this;
|
||||
|
||||
let existingHeader = getResponseHeader("Vary") ?? "";
|
||||
|
||||
if (
|
||||
existingHeader &&
|
||||
typeof existingHeader === "string" &&
|
||||
(existingHeader = appendVaryHeader(existingHeader, field))
|
||||
) {
|
||||
setResponseHeader("Vary", existingHeader);
|
||||
}
|
||||
};
|
||||
|
||||
private appendVaryHeader = (header: string, field: string) => {
|
||||
const { parseVaryHeader } = this;
|
||||
|
||||
if (header === "*") return header;
|
||||
|
||||
let varyHeader = header;
|
||||
const fields = parseVaryHeader(field);
|
||||
const headers = parseVaryHeader(header.toLocaleLowerCase());
|
||||
|
||||
if (fields.includes("*") || headers.includes("*")) return "*";
|
||||
|
||||
fields.forEach((field) => {
|
||||
const fld = field.toLowerCase();
|
||||
|
||||
if (headers.includes(fld)) {
|
||||
headers.push(fld);
|
||||
varyHeader = varyHeader ? `${varyHeader}, ${field}` : field;
|
||||
}
|
||||
});
|
||||
|
||||
return varyHeader;
|
||||
};
|
||||
|
||||
private parseVaryHeader = (header: string) => {
|
||||
let end = 0;
|
||||
const list = [];
|
||||
let start = 0;
|
||||
|
||||
for (let i = 0, len = header.length; i < len; i++) {
|
||||
switch (header.charCodeAt(i)) {
|
||||
case 0x20 /* */:
|
||||
if (start === end) start = end = i + 1;
|
||||
break;
|
||||
case 0x2c /* , */:
|
||||
list.push(header.substring(start, end));
|
||||
start = end = i + 1;
|
||||
break;
|
||||
default:
|
||||
end = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list.push(header.substring(start, end));
|
||||
|
||||
return list;
|
||||
};
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import type { CorsOptions, CorsOptionsDelegate } from "./types.ts";
|
||||
import { Cors } from "./cors.ts";
|
||||
|
||||
interface Req {
|
||||
serverRequest: {
|
||||
method: string;
|
||||
headers: {
|
||||
get(headerKey: string): string | null | undefined;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface Res {
|
||||
status?: number | string;
|
||||
headers: {
|
||||
get(headerKey: string): string | null | undefined;
|
||||
set(headerKey: string, headerValue: string): any;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* mithCors middleware wrapper
|
||||
* @param o CorsOptions | CorsOptionsDelegate
|
||||
* @link https://github.com/tajpouria/cors/blob/master/README.md#cors
|
||||
*/
|
||||
export const mithCors = <
|
||||
RequestT extends Req = any,
|
||||
ResponseT extends Res = any,
|
||||
MiddlewareT extends (
|
||||
request: RequestT,
|
||||
response: ResponseT,
|
||||
next: (...args: any) => any,
|
||||
) => any = any,
|
||||
>(
|
||||
o?: CorsOptions | CorsOptionsDelegate<RequestT>,
|
||||
) => {
|
||||
const corsOptionsDelegate = Cors.produceCorsOptionsDelegate<
|
||||
CorsOptionsDelegate<RequestT>
|
||||
>(o);
|
||||
|
||||
return (async (request, response, next) => {
|
||||
const serverRequest = request.serverRequest;
|
||||
try {
|
||||
const options = await corsOptionsDelegate(request);
|
||||
|
||||
const corsOptions = Cors.produceCorsOptions(options || {});
|
||||
const originDelegate = Cors.produceOriginDelegate(corsOptions);
|
||||
|
||||
if (originDelegate) {
|
||||
const requestMethod = serverRequest.method;
|
||||
const getRequestHeader = (headerKey: string) =>
|
||||
serverRequest.headers.get(headerKey);
|
||||
const getResponseHeader = (headerKey: string) =>
|
||||
response.headers.get(headerKey);
|
||||
const setResponseHeader = (headerKey: string, headerValue: string) =>
|
||||
response.headers.set(headerKey, headerValue);
|
||||
const setStatus = (
|
||||
statusCode: number,
|
||||
) => (response.status = statusCode);
|
||||
const end = () => {};
|
||||
|
||||
const origin = await originDelegate(getRequestHeader("origin"));
|
||||
|
||||
if (!origin) return next();
|
||||
else {
|
||||
corsOptions.origin = origin;
|
||||
|
||||
return new Cors({
|
||||
corsOptions,
|
||||
requestMethod,
|
||||
getRequestHeader,
|
||||
getResponseHeader,
|
||||
setResponseHeader,
|
||||
setStatus,
|
||||
next,
|
||||
end,
|
||||
}).configureHeaders();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return next();
|
||||
}) as MiddlewareT;
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export * from "./types.ts";
|
||||
|
||||
export { oakCors } from "./oakCors.ts";
|
||||
export { abcCors } from "./abcCors.ts";
|
||||
export { opineCors } from "./opineCors.ts";
|
||||
export { mithCors } from "./mithCors.ts";
|
||||
export { attainCors } from "./attainCors.ts";
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
import type { CorsOptions, CorsOptionsDelegate } from "./types.ts";
|
||||
import { Cors } from "./cors.ts";
|
||||
|
||||
interface Req {
|
||||
method: string;
|
||||
headers: {
|
||||
get(headerKey: string): string | null | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
interface Res {
|
||||
status?: number | string;
|
||||
headers: {
|
||||
get(headerKey: string): string | null | undefined;
|
||||
set(headerKey: string, headerValue: string): any;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* oakCors middleware wrapper
|
||||
* @param o CorsOptions | CorsOptionsDelegate
|
||||
* @link https://github.com/tajpouria/cors/blob/master/README.md#cors
|
||||
*/
|
||||
export const oakCors = <
|
||||
RequestT extends Req = any,
|
||||
ResponseT extends Res = any,
|
||||
MiddlewareT extends (
|
||||
context: { request: RequestT; response: ResponseT },
|
||||
next: (...args: any) => any,
|
||||
) => any = any,
|
||||
>(
|
||||
o?: CorsOptions | CorsOptionsDelegate<RequestT>,
|
||||
) => {
|
||||
const corsOptionsDelegate = Cors.produceCorsOptionsDelegate<
|
||||
CorsOptionsDelegate<RequestT>
|
||||
>(o);
|
||||
|
||||
return (async ({ request, response }, next) => {
|
||||
try {
|
||||
const options = await corsOptionsDelegate(request);
|
||||
|
||||
const corsOptions = Cors.produceCorsOptions(options || {});
|
||||
const originDelegate = Cors.produceOriginDelegate(corsOptions);
|
||||
|
||||
if (originDelegate) {
|
||||
const requestMethod = request.method;
|
||||
const getRequestHeader = (headerKey: string) =>
|
||||
request.headers.get(headerKey);
|
||||
const getResponseHeader = (headerKey: string) =>
|
||||
response.headers.get(headerKey);
|
||||
const setResponseHeader = (headerKey: string, headerValue: string) =>
|
||||
response.headers.set(headerKey, headerValue);
|
||||
const setStatus = (
|
||||
statusCode: number,
|
||||
) => (response.status = statusCode);
|
||||
const end = () => {};
|
||||
|
||||
const origin = await originDelegate(getRequestHeader("origin"));
|
||||
|
||||
if (!origin) next();
|
||||
else {
|
||||
corsOptions.origin = origin;
|
||||
|
||||
return new Cors({
|
||||
corsOptions,
|
||||
requestMethod,
|
||||
getRequestHeader,
|
||||
getResponseHeader,
|
||||
setResponseHeader,
|
||||
setStatus,
|
||||
next,
|
||||
end,
|
||||
}).configureHeaders();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
next();
|
||||
}) as MiddlewareT;
|
||||
};
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
import type { CorsOptions, CorsOptionsDelegate } from "./types.ts";
|
||||
import { Cors } from "./cors.ts";
|
||||
|
||||
interface Req {
|
||||
method: string;
|
||||
headers: {
|
||||
get(name: string): string | null | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
interface Res {
|
||||
setStatus(code: any): this;
|
||||
set(headerKey: string, headerValue: string): this;
|
||||
get(headerKey: string): string | null | undefined;
|
||||
end(...args: any): any;
|
||||
}
|
||||
|
||||
/**
|
||||
* opineCors middleware wrapper
|
||||
* @param o CorsOptions | CorsOptionsDelegate
|
||||
* @link https://github.com/tajpouria/cors/blob/master/README.md#cors
|
||||
*/
|
||||
export const opineCors = <
|
||||
RequestT extends Req = Req,
|
||||
ResponseT extends Res = any,
|
||||
MiddlewareT extends (
|
||||
request: RequestT,
|
||||
response: ResponseT,
|
||||
next: (...args: any) => any,
|
||||
) => any = any,
|
||||
>(
|
||||
o?: CorsOptions | CorsOptionsDelegate<RequestT>,
|
||||
) => {
|
||||
const corsOptionsDelegate = Cors.produceCorsOptionsDelegate<
|
||||
CorsOptionsDelegate<RequestT>
|
||||
>(o);
|
||||
|
||||
return (async (request, response, next) => {
|
||||
try {
|
||||
const options = await corsOptionsDelegate(request);
|
||||
|
||||
const corsOptions = Cors.produceCorsOptions(options || {});
|
||||
const originDelegate = Cors.produceOriginDelegate(corsOptions);
|
||||
|
||||
if (originDelegate) {
|
||||
const requestMethod = request.method;
|
||||
const getRequestHeader = (headerKey: string) =>
|
||||
request.headers.get(headerKey);
|
||||
const getResponseHeader = (headerKey: string) =>
|
||||
response.get(headerKey);
|
||||
const setResponseHeader = (headerKey: string, headerValue: string) =>
|
||||
response.set(headerKey, headerValue);
|
||||
const setStatus = (statusCode: number) =>
|
||||
response.setStatus(statusCode);
|
||||
const end = () => response.end();
|
||||
|
||||
const origin = await originDelegate(getRequestHeader("origin"));
|
||||
|
||||
if (!origin) return next();
|
||||
else {
|
||||
corsOptions.origin = origin;
|
||||
|
||||
return new Cors({
|
||||
corsOptions,
|
||||
requestMethod,
|
||||
getRequestHeader,
|
||||
getResponseHeader,
|
||||
setResponseHeader,
|
||||
setStatus,
|
||||
next,
|
||||
end,
|
||||
}).configureHeaders();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return next();
|
||||
}) as MiddlewareT;
|
||||
};
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* CorsOptions
|
||||
*
|
||||
* An Object that describes how CORS middleware should behave. The default configuration is the equivalent of:
|
||||
*
|
||||
* ```ts
|
||||
* {
|
||||
* "origin": "*",
|
||||
* "methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
|
||||
* "preflightContinue": false,
|
||||
* "optionsSuccessStatus": 204,
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @link https://github.com/tajpouria/cors#configuration-options
|
||||
*/
|
||||
export type CorsOptions = {
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Origin CORS header.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - Boolean
|
||||
*
|
||||
* set origin to true to reflect the request origin, as defined by req.header('Origin'):
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ origin: true }));
|
||||
*
|
||||
* ```
|
||||
* or set it to false to disable CORS:
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ origin: false }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* - 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:
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ origin: 'http://example.com' }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* - RegExp
|
||||
*
|
||||
* set origin to a regular expression pattern which will be used to test the request origin. If it's 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":
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ origin: /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":
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ origin: ["http://example1.com", /\.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 (called as callback(err, origin), where origin is a non-function value of the origin option) as the second:
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({
|
||||
* origin: async (requestOrigin) => {
|
||||
* await loadOriginsFromDataBase(); // Simulate asynchronous task
|
||||
* return ["http://example1.com", /\.example2\.com$/];
|
||||
* },
|
||||
* }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
origin?: boolean | string | RegExp | (string | RegExp)[] | OriginDelegate;
|
||||
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Methods CORS header.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - String
|
||||
*
|
||||
* Expects a comma-delimited string (ex: 'GET,PUT,POST'):
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ methods: 'GET,PUT,POST' }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* - Array
|
||||
*
|
||||
* or an array (ex: ['GET', 'PUT', 'POST'])
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ methods: ['GET', 'PUT', 'POST'] }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
methods?: string | string[];
|
||||
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Headers CORS header. If not specified, defaults to reflecting the headers specified in the request's Access-Control-Request-Headers header.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - String
|
||||
*
|
||||
* Expects a comma-delimited string (ex: 'Content-Type,Authorization'):
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ allowedHeaders: 'Content-Type,Authorization' }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* - Array
|
||||
*
|
||||
* or an array (ex: ['Content-Type', 'Authorization']):
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ allowedHeaders: ['Content-Type', 'Authorization'] }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
allowedHeaders?: string | string[];
|
||||
|
||||
/**
|
||||
* Configures the Access-Control-Expose-Headers CORS header. If not specified, no custom headers are exposed.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - String
|
||||
*
|
||||
* Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range'):
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ exposedHeaders: 'Content-Range,X-Content-Range' }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
exposedHeaders?: string | string[];
|
||||
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Credentials CORS header. It is omitted by default.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - Boolean
|
||||
*
|
||||
* Set to true to pass the header:
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ credentials: true }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
credentials?: boolean;
|
||||
|
||||
/**
|
||||
* Configures the Access-Control-Max-Age CORS header. It is omitted by default.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - Number
|
||||
*
|
||||
* Set to an integer to pass the header:
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ maxAge: 1 }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
maxAge?: number;
|
||||
|
||||
/**
|
||||
* Pass the CORS preflight response to the next handler:
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - Boolean
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ preflightContinue: true }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
preflightContinue?: boolean;
|
||||
|
||||
/**
|
||||
* Provides a status code to use for successful OPTIONS requests, since some legacy browsers (IE11, various SmartTVs) choke on 204.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - Number
|
||||
*
|
||||
* ```ts
|
||||
* app.use(cors({ optionsSuccessStatus: 200 }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
optionsSuccessStatus?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* @link https://github.com/tajpouria/cors#configuring-cors-w-dynamic-origin
|
||||
*/
|
||||
export type OriginDelegate = (
|
||||
requestOrigin: string | undefined | null,
|
||||
) => CorsOptions["origin"] | void | Promise<CorsOptions["origin"] | void>;
|
||||
|
||||
/**
|
||||
* @link https://github.com/tajpouria/cors#configuring-cors-asynchronously
|
||||
*/
|
||||
export type CorsOptionsDelegate<RequestT = any> = (
|
||||
request: RequestT,
|
||||
) => CorsOptions | void | Promise<CorsOptions | void>;
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"imports": {
|
||||
"https://deno.land/x/cors/mod.ts": "./deno.land/x/cors@v1.2.2/mod.ts",
|
||||
"https://deno.land/x/oak/mod.ts": "./deno.land/x/oak@v12.1.0/mod.ts",
|
||||
"https://deno.land/std/testing/asserts.ts": "./deno.land/std@0.191.0/testing/asserts.ts",
|
||||
"https://deno.land/": "./deno.land/"
|
||||
|
||||
Reference in new issue
Block a user