Skip to content
This repository was archived by the owner on Apr 8, 2024. It is now read-only.

Commit 2d52ae2

Browse files
authored
Merge pull request #9 from uniquelyparticular/feature/mustache-token-replacement
Feature/mustache token replacement
2 parents 28ee8ac + 5bc07fb commit 2d52ae2

File tree

5 files changed

+123
-8
lines changed

5 files changed

+123
-8
lines changed

README.md

+36-3
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,51 @@ Built with [Micro](https://github.com/zeit/micro)! 🤩
1111
Create a `.env` at the project root with the following credentials:
1212

1313
```dosini
14-
PROXY_PREFIX=proxy
1514
PROXY_REFERER_WHITELIST=localhost,*.zendesk.com,*.myshopify.com,*.now.sh
1615
PROXY_DESTINATION_WHITELIST=api.stripe.com,api.goshippo.com,api.shipengine.com,api.moltin.com,*.myshopify.com,*.salesforce.com,*.demandware.net
1716
```
1817

19-
`PROXY_PREFIX` is optional and will default to `'proxy'` but is used in the URI patterns to determine where to find the encoded uri to proxy request to (ie. `https://12345678.ngrok.io/<<<PROXY_PREFIX>>>/https%3A%2F%2Fapi.somethingsecure.com%2Fadmin%2Fcustomers.json`)
20-
2118
`PROXY_REFERER_WHITELIST` is a comma separated list of patterns to match against the incoming requests 'Referer' header (ex. `localhost,*.myawesomesite.com,*.now.sh`)
2219
_(and yes, 'REFERER' is intentionally misspelled to match the http header! 😉)_
2320

2421
`PROXY_DESTINATION_WHITELIST` is a comma separated list of patterns to match against the URI you are proxying requests to. (ex. `api.somethingsecure.com,*.somotherapi.com`)
2522

23+
_Optional Additional Parameters_
24+
const proxyReplacePrefix = process.env.PROXY*REPLACE || 'PROXY_REPLACE*'
25+
const proxyReplaceMatchPrefix = process.env.PROXY_REPLACE_MATCH || 'setting'
26+
27+
```dosini
28+
PROXY_PREFIX=proxy
29+
PROXY_REPLACE_MATCH=setting
30+
PROXY_REPLACE=PROXY_REPLACE_
31+
```
32+
33+
`PROXY_PREFIX` will default to `'proxy'` and is used in the URI patterns to determine where to find the encoded uri to proxy request to (ie. `https://12345678.ngrok.io/<<<PROXY_PREFIX>>>/https%3A%2F%2Fapi.somethingsecure.com%2Fadmin%2Fcustomers.json`)
34+
35+
`PROXY_REPLACE_MATCH` will default to `'setting'` and used within HTTP_HEADERS sent to the proxy to support Mustache like syntax `{{<<PROXY_REPLACE_MATCH>>.something_secure}}` to replace `something_secure` with a value found in your `process.env` (preceeded by your `PROXY_REPLACE` prefix)
36+
37+
`PROXY_REPLACE` will default to `'PROXY_REPLACE_'` and is the prefix used to look for other keys in your `process.env` that it will then use to override matched HTTP_HEADER values with
38+
39+
_Example_
40+
41+
```dosini
42+
PROXY_REPLACE_MATCH=setting
43+
PROXY_REPLACE=PROXY_REPLACE_
44+
PROXY_REPLACE_SOMETHING_SECURE=1XXXXXxxxxxXXXXXxxxxxXXXXXxxxxx1
45+
```
46+
47+
Which will then take something like the following HTTP_HEADER sent to the proxy:
48+
49+
```dosini
50+
{ 'X-Shopify-Access-Token', '{{setting.something_secure}}' }
51+
```
52+
53+
And before the request is proxied to the destination will inject your `process.env` value to send along in the proxied request:
54+
55+
```dosini
56+
{ 'X-Shopify-Access-Token', '1XXXXXxxxxxXXXXXxxxxxXXXXXxxxxx1' }
57+
```
58+
2659
## 📦 Package
2760

2861
Run the following command to build the app

direct.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const { filterByPrefix, mustachReplace } = require('./src/utils')
2+
3+
process.on('unhandledRejection', (reason, p) => {
4+
console.error(
5+
'Promise unhandledRejection: ',
6+
p,
7+
', reason:',
8+
JSON.stringify(reason)
9+
)
10+
})
11+
12+
process.env.PROXY_REPLACE_FOO = 'very-secret-23234-324234-234'
13+
14+
class Direct {
15+
static async run() {
16+
const secureHeader = 'asdas {{settings.foo}} sadsad'
17+
console.log('secureHeader', secureHeader)
18+
const replacements = filterByPrefix(process.env, 'PROXY_REPLACE_')
19+
console.log('replacements', replacements)
20+
const header = mustachReplace(secureHeader, replacements, 'setting')
21+
console.log('header', header)
22+
}
23+
}
24+
25+
module.exports = Direct
26+
27+
if (require.main === module) {
28+
Direct.run()
29+
}

now.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
"NODE_ENV": "production",
66
"PROXY_PREFIX": "@demo-proxy-prefix",
77
"PROXY_REFERER_WHITELIST": "@demo-proxy-referer-whitelist",
8-
"PROXY_DESTINATION_WHITELIST": "@demo-proxy-destination-whitelist"
8+
"PROXY_DESTINATION_WHITELIST": "@demo-proxy-destination-whitelist",
9+
"PROXY_REPLACE_GATEWAY_PK": "@particular-gateway-pk",
10+
"PROXY_REPLACE_GATEWAY_SK": "@particular-gateway-sk"
911
},
1012
"routes": [{ "src": "/(.*)", "dest": "/src" }],
1113
"builds": [

src/index.js

+20-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const { URL } = require('whatwg-url')
55
const UrlPattern = require('url-pattern')
66
const cors = require('micro-cors')()
77
const fetch = require('node-fetch')
8+
const { filterByPrefix, mustachReplace } = require('./utils')
89

910
const _toJSON = error => {
1011
return !error
@@ -74,24 +75,39 @@ const destinationWhiteList = toRegexArray(
7475
process.env.PROXY_DESTINATION_WHITELIST
7576
)
7677
const proxyPrefix = process.env.PROXY_PREFIX || 'proxy'
77-
// console.log('process.env.PROXY_PREFIX', process.env.PROXY_PREFIX)
78+
const proxyReplacePrefix = process.env.PROXY_REPLACE || 'PROXY_REPLACE_'
79+
const proxyReplaceMatchPrefix = process.env.PROXY_REPLACE_MATCH || 'setting'
80+
// console.log('process.env.PROXY_PREFIX', proxyPrefix)
81+
// console.log('process.env.PROXY_REPLACE', proxyReplacePrefix)
82+
// console.log('process.env.PROXY_REPLACE_MATCH', proxyReplaceMatchPrefix)
83+
const envReplacements = filterByPrefix(process.env, proxyReplacePrefix)
84+
// console.log('envReplacements', envReplacements)
85+
86+
const filterValue = input => {
87+
return mustachReplace(input, envReplacements, proxyReplaceMatchPrefix)
88+
}
7889

7990
const requestHeaders = headers => {
80-
console.log('requestHeaders, headers', headers)
8191
const {
8292
host,
8393
referer,
8494
origin,
8595
'x-requested-with': requestedWith,
86-
...filteredHeaders
96+
...filteringHeaders
8797
} = headers
98+
99+
const filteredHeaders = Object.keys(filteringHeaders).reduce((obj, key) => {
100+
obj[key] = filterValue(filteringHeaders[key])
101+
return obj
102+
}, {})
103+
88104
const defaultHeaders = {
89105
'x-forwarded-by': `${name}-${version}`,
90106
'x-forwarded-origin': origin,
91107
'x-forwarded-referer': referer
92108
}
93109
const modifiedHeaders = { ...filteredHeaders, ...defaultHeaders }
94-
// console.log('requestHeaders, modifiedHeaders', modifiedHeaders)
110+
console.log('requestHeaders, modifiedHeaders', modifiedHeaders)
95111
return modifiedHeaders
96112
}
97113

src/utils.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module.exports = {
2+
filterByPrefix(input, ...matchPrefixes) {
3+
return Object.keys(input)
4+
.filter(key => {
5+
// return only objects within input who's keys start with any envPrefix
6+
let matched = false
7+
matchPrefixes.forEach(prefix => {
8+
matched = matched || key.startsWith(prefix)
9+
})
10+
return matched
11+
})
12+
.reduce((obj, rawKey) => {
13+
// remove any envPrefix that object startswith
14+
let key = rawKey
15+
matchPrefixes.forEach(prefix => {
16+
key = key.startsWith(prefix) ? key.replace(prefix, '') : key
17+
})
18+
obj[key] = input[rawKey]
19+
return obj
20+
}, {})
21+
},
22+
23+
mustachReplace(input, replacements, ...mustachPrefixes) {
24+
// will search for input containing {{mustachePrefix.XYZ}}
25+
return input.replace(/{{((.*?)\.(.*?))}}/g, (match, ...groups) => {
26+
if (mustachPrefixes.includes(groups[1])) {
27+
return groups[2] !== 'undefined'
28+
? replacements[groups[2].toUpperCase()] || match
29+
: match
30+
} else {
31+
return match
32+
}
33+
})
34+
}
35+
}

0 commit comments

Comments
 (0)