Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add headers in proxy #36

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
84d4ac5
feature(): Don't crash on error return err
Samox May 31, 2022
bdb31de
feature(): Open the webhook store
Samox May 31, 2022
a60803e
feature(): Simplify API
Samox May 31, 2022
db6489c
feature(): Remove useless logs
Samox May 31, 2022
7bfef74
chore(): Try a npm package publication
Samox May 31, 2022
ef20dbc
feature(): Add help
Samox Jun 1, 2022
75b2f47
chore(): Fix style
Samox Jun 1, 2022
72233de
chore(): Bump version
Samox Jun 2, 2022
b9484c7
feature(): Prompt for a domain instead of throwing an error
Samox Jun 6, 2022
ccd4eb6
feature(): Display response code in terminal
Samox Jun 6, 2022
f6ec8b9
feature(): Improved webhookStore url prompt
Samox Jun 6, 2022
d530c1b
feature(): Wait before opening store
Samox Jun 6, 2022
86bc598
feature(): Add a healthcheck
Samox Jun 6, 2022
6bf9961
chore(): Bump version
Samox Jun 6, 2022
2223c36
refactor(lcp): remove old parameter partialProxy
Samox Jul 12, 2022
9fee485
feature(Option): Allow a noOpen option
Samox Jul 13, 2022
07779ef
bugfix(option): Display warning when port is not set
Samox Jul 13, 2022
fe7258d
Merge pull request #1 from OpenWebhook/add-healthcheck
Samox Jul 13, 2022
6467c23
bump version
Samox Jul 13, 2022
02b7aa9
feature(Cli): Prompt port if not provided
Samox Jul 13, 2022
2ff65de
feature(Cli): options for protocol and hostname
rbideau Feb 27, 2023
b014876
Merge pull request #2 from DotfileTech/hostname-protocol-options
Samox Mar 9, 2023
1a35bb0
docs: update readme options
Samox Mar 9, 2023
1fd2459
chore: bump version
Samox Mar 9, 2023
4d881c2
docs: recommend latest version
Samox Mar 9, 2023
213fed1
feat: add orignal headers in the request
Samox Apr 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 Gary Meehan
Copyright (c) 2018 Sammy Teillet

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
44 changes: 23 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Local CORS Proxy
# Local CORS Proxy + Webhook Store

Simple proxy to bypass CORS issues. This was built as a local dev only solution to enable prototyping against existing APIs without having to worry about CORS.

Expand All @@ -11,45 +11,47 @@ No 'Access-Control-Allow-Origin' header is present on the requested resource. Or
## Getting Started

```
npm install -g local-cors-proxy
npx webhook-store-cli@latest
```

**Simple Example**

API endpoint that we want to request that has CORS issues:
Start Proxy and open Webhook Store client in a tab:

```
https://www.yourdomain.ie/movies/list
npx webhook-store-cli@latest
```

Start Proxy:
Start Proxy and open a specific Webhook Store client:

```
lcp --proxyUrl https://www.yourdomain.ie
npx webhook-store-cli@latest --webhookStore https://lol.webhook.store/
```

Then in your client code, new API endpoint:
Start Proxy without opening a tab:

```
http://localhost:8010/proxy/movies/list
npx webhook-store-cli@latest --noOpen
```

End result will be a request to `https://www.yourdomain.ie/movies/list` without the CORS issues!
Start Proxy to target port 9000:

Alternatively you can install the package locally and add a script to your project:
```
npx webhook-store-cli@latest --port 9000
```

```json
"scripts": {
"proxy": "lcp --proxyUrl https://www.yourdomain.ie"
}
Start Proxy to target specific port, hostname and protocol:

```
npx webhook-store-cli@latest --protocol https --hostname dev.localenv --port 9000
```

## Options

| Option | Example | Default |
| -------------- | --------------------- | ------: |
| --proxyUrl | https://www.google.ie | |
| --proxyPartial | foo | proxy |
| --port | 8010 | 8010 |
| --credentials | (no value needed) | false |
| --origin | http://localhost:4200 | * |
| Option | Example | Default |
| -------------- | ------------------------- | --------: |
| --webhookStore | https://lol.webhook.store | |
| --noOpen | (no value needed) | |
| --port | 9000 | 9000 |
| --protocol | https | http |
| --hostname | dev.localenv | localhost |
91 changes: 78 additions & 13 deletions bin/lcp.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,91 @@
#!/usr/bin/env node

var lcp = require('../lib/index.js');
var commandLineArgs = require('command-line-args');
var lcp = require("../lib/index.js");
var commandLineArgs = require("command-line-args");
var chalk = require("chalk");
const prompt = require("prompt-sync")();

var optionDefinitions = [
{ name: 'port', alias: 'p', type: Number, defaultValue: 8010 },
{ name: "proxyPort", alias: "p", type: Number, defaultValue: 8010 },
{ name: "protocol", type: String, defaultValue: "http" },
{ name: "hostname", type: String, defaultValue: "localhost" },
{ name: "port", type: String },
{ name: "credentials", type: Boolean, defaultValue: false },
{ name: "origin", type: String, defaultValue: "*" },
{ name: "webhookStore", type: String },
{ name: "noOpen", type: Boolean, default: false },
{
name: 'proxyPartial',
type: String,
defaultValue: '/proxy'
name: "help",
type: Boolean,
alias: "h",
description: "print out helpful usage information",
},
{ name: 'proxyUrl', type: String },
{ name: 'credentials', type: Boolean, defaultValue: false },
{ name: 'origin', type: String, defaultValue: '*' }
];

function getDefaultSubdomain() {
const defaultSubdomain = "hackator10";
try {
const username = require("os").userInfo().username;
return username.replace(/[^a-zA-Z0-9]/g, "") || defaultSubdomain;
} catch {
return defaultSubdomain;
}
}

try {
var options = commandLineArgs(optionDefinitions);
if (!options.proxyUrl) {
throw new Error('--proxyUrl is required');
if (options.help) {
console.warn(chalk.yellow.bold("Options"));
console.warn(
chalk.yellow(
"webhookStore: " +
chalk.green(
"Url of you webhook store. Example: --webhookStore https://coucou.webhook.store"
)
)
);
console.warn(
chalk.yellow(
"port: " +
chalk.green(
"The port you want forward the webhooks. Example: --port 9001"
)
)
);
} else {
if (!options.webhookStore && !options.noOpen) {
console.log(chalk.yellow("--webhookStore was not provided."));
const defaultSubdomain = getDefaultSubdomain();
const subdomainInput =
prompt(
`Claim your subdomain (your name or company name. e.g. ${defaultSubdomain}): `
) || defaultSubdomain;
const subdomain =
subdomainInput.replace(/[^a-zA-Z0-9]/g, "") || defaultSubdomain;
options.webhookStore = `https://${subdomain}.webhook.store`;
console.log(
chalk.yellow(
`Next time run with '--webhookStore ${options.webhookStore}'`
)
);
}
if (!options.port) {
console.log(chalk.yellow("--port option was not provided"));
const portInput =
prompt(
`Which port would you like to redirect webhooks on (default :9000): `
) || 9000;
options.port = isNaN(portInput) ? 9000 : portInput;
}
lcp.startProxy(
options.proxyPort,
options.protocol + "://" + options.hostname + ":" + options.port,
options.credentials,
options.origin,
options.webhookStore,
options.noOpen
);
}
lcp.startProxy(options.port, options.proxyUrl, options.proxyPartial, options.credentials, options.origin);
} catch (error) {
console.error(error);
console.error(chalk.red(error));
}
101 changes: 66 additions & 35 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,81 @@
var express = require('express');
var request = require('request');
var cors = require('cors');
var chalk = require('chalk');
var express = require("express");
var request = require("request");
var cors = require("cors");
var chalk = require("chalk");
var open = require("open");
var proxy = express();

var startProxy = function(port, proxyUrl, proxyPartial, credentials, origin) {
proxy.use(cors({credentials: credentials, origin: origin}));
proxy.options('*', cors({credentials: credentials, origin: origin}));
var startProxy = function (
port,
proxyUrl,
credentials,
origin,
webhookStoreUrl,
shouldNotOpen
) {
proxy.use(cors({ credentials: credentials, origin: origin }));
proxy.options("*", cors({ credentials: credentials, origin: origin }));

// remove trailing slash
var cleanProxyUrl = proxyUrl.replace(/\/$/, '');
// remove all forward slashes
var cleanProxyPartial = proxyPartial.replace(/\//g, '');
var cleanProxyUrl = proxyUrl.replace(/\/$/, "");
var cleanProxyPartial = "proxy";

proxy.use('/' + cleanProxyPartial, function(req, res) {
proxy.use("/" + cleanProxyPartial, function (req, res, next) {
try {
console.log(chalk.green('Request Proxied -> ' + req.url));
console.log(chalk.green("Request Proxied -> " + req.url));

var originalHeaders = JSON.parse(req.headers["x-ws-original-headers"]);
Object.keys(originalHeaders).forEach(function (key) {
req.headers[key] = originalHeaders[key];
});
} catch (e) {}
req.pipe(
request(cleanProxyUrl + req.url)
.on('response', response => {
// In order to avoid https://github.com/expressjs/cors/issues/134
const accessControlAllowOriginHeader = response.headers['access-control-allow-origin']
if(accessControlAllowOriginHeader && accessControlAllowOriginHeader !== origin ){
console.log(chalk.blue('Override access-control-allow-origin header from proxified URL : ' + chalk.green(accessControlAllowOriginHeader) + '\n'));
response.headers['access-control-allow-origin'] = origin;
}
})
).pipe(res);
req
.pipe(
request(cleanProxyUrl + req.url)
.on("response", (response) => {
console.log(chalk.blue("Response code: " + response.statusCode));
// In order to avoid https://github.com/expressjs/cors/issues/134
const accessControlAllowOriginHeader =
response.headers["access-control-allow-origin"];
if (
accessControlAllowOriginHeader &&
accessControlAllowOriginHeader !== origin
) {
console.log(
chalk.blue(
"Override access-control-allow-origin header from proxified URL : " +
chalk.green(accessControlAllowOriginHeader) +
"\n"
)
);
response.headers["access-control-allow-origin"] = origin;
}
})
.on("error", next)
)
.pipe(res);
});

proxy.use("/health", (_req, res) => {
res.send("ok");
});

proxy.listen(port);

// Welcome Message
console.log(chalk.bgGreen.black.bold.underline('\n Proxy Active \n'));
console.log(chalk.blue('Proxy Url: ' + chalk.green(cleanProxyUrl)));
console.log(chalk.blue('Proxy Partial: ' + chalk.green(cleanProxyPartial)));
console.log(chalk.blue('PORT: ' + chalk.green(port)));
console.log(chalk.blue('Credentials: ' + chalk.green(credentials)));
console.log(chalk.blue('Origin: ' + chalk.green(origin) + '\n'));
console.log(
chalk.cyan(
'To start using the proxy simply replace the proxied part of your url with: ' +
chalk.bold('http://localhost:' + port + '/' + cleanProxyPartial + '\n')
)
);
console.log(chalk.bgGreen.black.bold.underline("\n Proxy Active \n"));
console.log(chalk.blue("Proxy Url: " + chalk.green(cleanProxyUrl)));
const shouldOpen = !shouldNotOpen;
if (shouldOpen) {
console.log(
chalk.blue("Webhook Store: " + chalk.green(webhookStoreUrl) + "\n")
);

console.log(
chalk.cyan("Now opening the webhook store " + chalk.bold(webhookStoreUrl))
);
setTimeout(open, 1000, webhookStoreUrl);
}
};

exports.startProxy = startProxy;
21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "local-cors-proxy",
"version": "1.1.0",
"name": "webhook-store-cli",
"version": "1.1.5",
"main": "./lib/index.js",
"scripts": {
"start": "node ./bin/lcp.js",
Expand All @@ -9,28 +9,29 @@
"bin": {
"lcp": "./bin/lcp.js"
},
"author": "Gary Meehan",
"author": "Sammy Teillet",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/garmeeh/local-cors-proxy.git"
"url": "git+https://github.com/OpenWebhook/webhook-store-cli.git"
},
"keywords": [
"cors",
"proxy",
"simple",
"node",
"express"
"webhook",
"webhook-store",
"dev-tool"
],
"bugs": {
"url": "https://github.com/garmeeh/local-cors-proxy/issues"
"url": "https://github.com/OpenWebhook/webhook-store-cli/issues"
},
"homepage": "https://github.com/garmeeh/local-cors-proxy#readme",
"homepage": "https://github.com/OpenWebhook/webhook-store-cli#readme",
"dependencies": {
"chalk": "^2.3.2",
"command-line-args": "^5.0.2",
"cors": "^2.8.4",
"express": "^4.16.3",
"open": "^8.4.0",
"prompt-sync": "^4.2.0",
"request": "^2.85.0"
}
}
Loading