├── .husky ├── .gitignore └── pre-commit ├── Procfile ├── .dockerignore ├── .babelrc ├── .editorconfig ├── .travis.yml ├── Dockerfile ├── .eslintrc ├── index.js ├── .gitignore ├── jest.config.js ├── package.json └── README.md /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | npm run test 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # @see: https://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12 4 | - 13 5 | - 14 6 | - 15 7 | - 16 8 | - 17 9 | script: 10 | - npm run ci && cat coverage/lcov.info | ./node_modules/.bin/jest --passWithNoTests && rm -rf coverage 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM node:14.16.0 4 | 5 | WORKDIR /app 6 | 7 | COPY ["package.json", "package-lock.json*", "./"] 8 | 9 | RUN npm install --production 10 | 11 | COPY . . 12 | 13 | CMD [ "node", "index.js" ] 14 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "airbnb", 4 | "plugins": ["jest"], 5 | "env": { 6 | "jest/globals": true 7 | }, 8 | "rules": { 9 | "no-bitwise": "off", 10 | "no-lonely-if": "off", 11 | "class-methods-use-this": "off", 12 | "arrow-body-style": "off", 13 | "no-loop-func": "off" 14 | }, 15 | "settings": { 16 | "react": { 17 | "version": "latest" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import request from 'request'; 3 | import cors from 'cors'; 4 | 5 | const app = express(); 6 | 7 | const port = process.env.PORT || 7979; 8 | const originAllowList = process.env.ORIGIN_ALLOW_LIST; 9 | 10 | app.use(cors()); 11 | 12 | // eslint-disable-next-line no-useless-escape 13 | app.use('/:url(https?:\/\/[a-zA-Z\.\-0-9\/]*)', (req, res) => { 14 | const origin = req.headers.origin || ''; 15 | if (originAllowList && originAllowList.length && originAllowList.indexOf(origin) === -1) { 16 | res.writeHead(403, 'Forbidden'); 17 | res.end(`HTTP request origin ${origin} was not whitelisted for this proxy ${req.protocol}://${req.headers.host}. Please set environment variable ORIGIN_ALLOW_LIST to ${origin}.`); 18 | return; 19 | } 20 | 21 | const { url } = req.params; 22 | req.pipe(request(url)).pipe(res); 23 | }); 24 | 25 | app.listen(port); 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # IntelliJ IDE 64 | .idea/ 65 | 66 | # Mac specific 67 | .DS_Store 68 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // The bail config option can be used here to have Jest stop running tests after 3 | // the first failure. 4 | bail: false, 5 | 6 | // Indicates whether each individual test should be reported during the run. 7 | verbose: false, 8 | 9 | // Indicates whether the coverage information should be collected while executing the test 10 | collectCoverage: false, 11 | 12 | // The directory where Jest should output its coverage files. 13 | coverageDirectory: './coverage/', 14 | 15 | // If the test path matches any of the patterns, it will be skipped. 16 | testPathIgnorePatterns: ['/node_modules/'], 17 | 18 | // If the file path matches any of the patterns, coverage information will be skipped. 19 | coveragePathIgnorePatterns: ['/node_modules/'], 20 | 21 | // The pattern Jest uses to detect test files. 22 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(js|jsx)?$', 23 | 24 | // This option sets the URL for the jsdom environment. 25 | // It is reflected in properties such as location.href. 26 | // @see: https://github.com/facebook/jest/issues/6769 27 | testURL: 'http://localhost/', 28 | 29 | // @see: https://jestjs.io/docs/en/configuration#coveragethreshold-object 30 | coverageThreshold: { 31 | global: { 32 | statements: 100, 33 | branches: 95, 34 | functions: 100, 35 | lines: 100, 36 | }, 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "https-cors-proxy", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "description": "Simple yet powerful HTTPS reverse-proxy to enable CORS.", 6 | "main": "index.js", 7 | "scripts": { 8 | "lint": "eslint '**/*.{js,jsx}'", 9 | "lint:fix": "eslint '**/*.{js,jsx}' --fix", 10 | "start": "node ./index.js", 11 | "test": "jest --verbose --passWithNoTests", 12 | "coverage": "npm run test -- --coverage", 13 | "ci": "npm run lint && npm run coverage", 14 | "prepare": "husky install" 15 | }, 16 | "keywords": [ 17 | "http", 18 | "cors", 19 | "proxy" 20 | ], 21 | "author": "DocuSign Developer Center ", 22 | "contributors": [ 23 | "https://github.com/docusign/cors-proxy/contributors" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/docusign/cors-proxy.git" 28 | }, 29 | "devDependencies": { 30 | "@babel/cli": "7.15.7", 31 | "@babel/preset-env": "7.15.8", 32 | "@types/jest": "27.0.2", 33 | "eslint": "7.14.0", 34 | "eslint-config-airbnb": "18.2.1", 35 | "eslint-plugin-import": "2.25.2", 36 | "eslint-plugin-jest": "25.2.2", 37 | "eslint-plugin-jsx-a11y": "6.4.1", 38 | "eslint-plugin-react": "7.26.1", 39 | "husky": "7.0.2", 40 | "jest": "27.3.0" 41 | }, 42 | "license": "MIT", 43 | "dependencies": { 44 | "cors": "^2.8.5", 45 | "express": "^4.17.2", 46 | "request": "^2.88.2" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cors-proxy 2 | Simple yet powerful HTTPS reverse-proxy to enable CORS. 3 | 4 | ## Usage 5 | Once the project or Docker image is deployed to an host, you can perform any HTTP call. For instance if the host IP address is 123.456.789.012 and the port being used is 7979 (default) then a basic GET call would be like: 6 | ```bash 7 | curl http://123.456.789.012:7979/https://demo.docusign.net/restapi 8 | ``` 9 | 10 | 11 | ## Deploy to AWS EC2 12 | ```bash 13 | sudo yum update -y 14 | sudo amazon-linux-extras install docker 15 | sudo yum install docker 16 | sudo service docker start 17 | sudo systemctl enable docker 18 | sudo docker pull dsdevcenter/cors-proxy 19 | sudo docker run -d --name cors-proxy-container -p 7979:7979 -e ORIGIN_ALLOW_LIST=https://example.com dsdevcenter/cors-proxy 20 | ``` 21 | 22 | ## Deploy to Azure 23 | ```bash 24 | docker login azure 25 | docker context create aci corsproxycontext 26 | docker context use corsproxycontext 27 | docker run -d --name cors-proxy-container -p 7979:7979 -e ORIGIN_ALLOW_LIST=https://example.com dsdevcenter/cors-proxy 28 | ``` 29 | 30 | The last command might take a while. Once it's done list Docker containers under `corsproxycontext` ACI context in order to view the host name and port: 31 | ```bash 32 | docker ps 33 | # CONTAINER ID IMAGE COMMAND STATUS PORTS 34 | # cors-proxy-container dsdevcenter/cors-proxy Running 123.456.789.012:7979->7979/tcp 35 | ``` 36 | 37 | ## Deploy to Heroku 38 | ```bash 39 | heroku login 40 | heroku create 41 | heroku config:set ORIGIN_ALLOW_LIST=https://example.com 42 | git commit -m "first commit" 43 | git push heroku main 44 | ``` 45 | 46 | Heroku deploys apps to HTTPS port 443 by default so you can test the setup by running: 47 | ```bash 48 | curl https://.herokuapp.com/https://demo.docusign.net/restapi 49 | ``` 50 | 51 | ## Deploy to any Linux-like environment 52 | ```bash 53 | docker pull dsdevcenter/cors-proxy 54 | docker run -d --name cors-proxy-container -p 7979:7979 -e ORIGIN_ALLOW_LIST=https://example.com dsdevcenter/cors-proxy 55 | ``` 56 | 57 | ## Docker setup 58 | ### Image creation 59 | ```bash 60 | docker build --tag cors-proxy . 61 | ``` 62 | 63 | ### Container creation 64 | ```bash 65 | docker run -d --name cors-proxy-container -p 7979:7979 -e ORIGIN_ALLOW_LIST=https://example.com dsdevcenter/cors-proxy 66 | ``` 67 | --------------------------------------------------------------------------------