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

Commit

Permalink
Merge pull request #9 from uniquelyparticular/feature/mustache-token-…
Browse files Browse the repository at this point in the history
…replacement

Feature/mustache token replacement
  • Loading branch information
agrohs authored May 24, 2019
2 parents 28ee8ac + 5bc07fb commit 2d52ae2
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 8 deletions.
39 changes: 36 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,51 @@ Built with [Micro](https://github.com/zeit/micro)! 🤩
Create a `.env` at the project root with the following credentials:

```dosini
PROXY_PREFIX=proxy
PROXY_REFERER_WHITELIST=localhost,*.zendesk.com,*.myshopify.com,*.now.sh
PROXY_DESTINATION_WHITELIST=api.stripe.com,api.goshippo.com,api.shipengine.com,api.moltin.com,*.myshopify.com,*.salesforce.com,*.demandware.net
```

`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`)

`PROXY_REFERER_WHITELIST` is a comma separated list of patterns to match against the incoming requests 'Referer' header (ex. `localhost,*.myawesomesite.com,*.now.sh`)
_(and yes, 'REFERER' is intentionally misspelled to match the http header! 😉)_

`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`)

_Optional Additional Parameters_
const proxyReplacePrefix = process.env.PROXY*REPLACE || 'PROXY_REPLACE*'
const proxyReplaceMatchPrefix = process.env.PROXY_REPLACE_MATCH || 'setting'

```dosini
PROXY_PREFIX=proxy
PROXY_REPLACE_MATCH=setting
PROXY_REPLACE=PROXY_REPLACE_
```

`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`)

`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)

`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

_Example_

```dosini
PROXY_REPLACE_MATCH=setting
PROXY_REPLACE=PROXY_REPLACE_
PROXY_REPLACE_SOMETHING_SECURE=1XXXXXxxxxxXXXXXxxxxxXXXXXxxxxx1
```

Which will then take something like the following HTTP_HEADER sent to the proxy:

```dosini
{ 'X-Shopify-Access-Token', '{{setting.something_secure}}' }
```

And before the request is proxied to the destination will inject your `process.env` value to send along in the proxied request:

```dosini
{ 'X-Shopify-Access-Token', '1XXXXXxxxxxXXXXXxxxxxXXXXXxxxxx1' }
```

## 📦 Package

Run the following command to build the app
Expand Down
29 changes: 29 additions & 0 deletions direct.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const { filterByPrefix, mustachReplace } = require('./src/utils')

process.on('unhandledRejection', (reason, p) => {
console.error(
'Promise unhandledRejection: ',
p,
', reason:',
JSON.stringify(reason)
)
})

process.env.PROXY_REPLACE_FOO = 'very-secret-23234-324234-234'

class Direct {
static async run() {
const secureHeader = 'asdas {{settings.foo}} sadsad'
console.log('secureHeader', secureHeader)
const replacements = filterByPrefix(process.env, 'PROXY_REPLACE_')
console.log('replacements', replacements)
const header = mustachReplace(secureHeader, replacements, 'setting')
console.log('header', header)
}
}

module.exports = Direct

if (require.main === module) {
Direct.run()
}
4 changes: 3 additions & 1 deletion now.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"NODE_ENV": "production",
"PROXY_PREFIX": "@demo-proxy-prefix",
"PROXY_REFERER_WHITELIST": "@demo-proxy-referer-whitelist",
"PROXY_DESTINATION_WHITELIST": "@demo-proxy-destination-whitelist"
"PROXY_DESTINATION_WHITELIST": "@demo-proxy-destination-whitelist",
"PROXY_REPLACE_GATEWAY_PK": "@particular-gateway-pk",
"PROXY_REPLACE_GATEWAY_SK": "@particular-gateway-sk"
},
"routes": [{ "src": "/(.*)", "dest": "/src" }],
"builds": [
Expand Down
24 changes: 20 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { URL } = require('whatwg-url')
const UrlPattern = require('url-pattern')
const cors = require('micro-cors')()
const fetch = require('node-fetch')
const { filterByPrefix, mustachReplace } = require('./utils')

const _toJSON = error => {
return !error
Expand Down Expand Up @@ -74,24 +75,39 @@ const destinationWhiteList = toRegexArray(
process.env.PROXY_DESTINATION_WHITELIST
)
const proxyPrefix = process.env.PROXY_PREFIX || 'proxy'
// console.log('process.env.PROXY_PREFIX', process.env.PROXY_PREFIX)
const proxyReplacePrefix = process.env.PROXY_REPLACE || 'PROXY_REPLACE_'
const proxyReplaceMatchPrefix = process.env.PROXY_REPLACE_MATCH || 'setting'
// console.log('process.env.PROXY_PREFIX', proxyPrefix)
// console.log('process.env.PROXY_REPLACE', proxyReplacePrefix)
// console.log('process.env.PROXY_REPLACE_MATCH', proxyReplaceMatchPrefix)
const envReplacements = filterByPrefix(process.env, proxyReplacePrefix)
// console.log('envReplacements', envReplacements)

const filterValue = input => {
return mustachReplace(input, envReplacements, proxyReplaceMatchPrefix)
}

const requestHeaders = headers => {
console.log('requestHeaders, headers', headers)
const {
host,
referer,
origin,
'x-requested-with': requestedWith,
...filteredHeaders
...filteringHeaders
} = headers

const filteredHeaders = Object.keys(filteringHeaders).reduce((obj, key) => {
obj[key] = filterValue(filteringHeaders[key])
return obj
}, {})

const defaultHeaders = {
'x-forwarded-by': `${name}-${version}`,
'x-forwarded-origin': origin,
'x-forwarded-referer': referer
}
const modifiedHeaders = { ...filteredHeaders, ...defaultHeaders }
// console.log('requestHeaders, modifiedHeaders', modifiedHeaders)
console.log('requestHeaders, modifiedHeaders', modifiedHeaders)
return modifiedHeaders
}

Expand Down
35 changes: 35 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module.exports = {
filterByPrefix(input, ...matchPrefixes) {
return Object.keys(input)
.filter(key => {
// return only objects within input who's keys start with any envPrefix
let matched = false
matchPrefixes.forEach(prefix => {
matched = matched || key.startsWith(prefix)
})
return matched
})
.reduce((obj, rawKey) => {
// remove any envPrefix that object startswith
let key = rawKey
matchPrefixes.forEach(prefix => {
key = key.startsWith(prefix) ? key.replace(prefix, '') : key
})
obj[key] = input[rawKey]
return obj
}, {})
},

mustachReplace(input, replacements, ...mustachPrefixes) {
// will search for input containing {{mustachePrefix.XYZ}}
return input.replace(/{{((.*?)\.(.*?))}}/g, (match, ...groups) => {
if (mustachPrefixes.includes(groups[1])) {
return groups[2] !== 'undefined'
? replacements[groups[2].toUpperCase()] || match
: match
} else {
return match
}
})
}
}

0 comments on commit 2d52ae2

Please sign in to comment.