Added Elasticsearch proxy example (#1398)
Co-authored-by: István Zoltán Szabó <istvan.szabo@elastic.co>
This commit is contained in:
committed by
delvedor
parent
7448cd3d24
commit
176d823593
@ -71,7 +71,7 @@ npm install @elastic/elasticsearch@<major>
|
|||||||
#### Browser
|
#### Browser
|
||||||
|
|
||||||
WARNING: There is no official support for the browser environment. It exposes your Elasticsearch instance to everyone, which could lead to security issues.
|
WARNING: There is no official support for the browser environment. It exposes your Elasticsearch instance to everyone, which could lead to security issues.
|
||||||
We recommend that you write a lightweight proxy that uses this client instead.
|
We recommend that you write a lightweight proxy that uses this client instead, you can see a proxy example [here](./docs/examples/proxy).
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|||||||
51
docs/examples/proxy/.gitignore
vendored
Normal file
51
docs/examples/proxy/.gitignore
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# coverage output
|
||||||
|
coverage.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules
|
||||||
|
jspm_packages
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# mac files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# vim swap files
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
#Jetbrains editor folder
|
||||||
|
.idea
|
||||||
|
|
||||||
|
.vercel
|
||||||
65
docs/examples/proxy/README.md
Normal file
65
docs/examples/proxy/README.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Elasticsearch proxy example
|
||||||
|
|
||||||
|
This folder contains an example of how to build a lightweight proxy
|
||||||
|
between your frontend code and Elasticsearch if you don't
|
||||||
|
have a more sophisticated backend in place yet.
|
||||||
|
|
||||||
|
> **IMPORTANT:** This is not a production ready code and it is only for demonstration purposes,
|
||||||
|
> we make no guarantees on it's security and stability.
|
||||||
|
|
||||||
|
This project is designed to be deployed on [Vercel](https://vercel.com/), a cloud platform
|
||||||
|
for static sites and Serverless Functions. You can use other functions providers,
|
||||||
|
such as [Google Cloud functions](https://cloud.google.com/functions).
|
||||||
|
|
||||||
|
## Project structure
|
||||||
|
|
||||||
|
The project comes with four endpoints:
|
||||||
|
|
||||||
|
- `/api/search`: runs a search, requires `'read'` permission
|
||||||
|
- `/api/autocomplete`: runs an autocomplete suggestion, requires `'read'` permission
|
||||||
|
- `/api/index`: indexes or updates a document, requires `'write'` permission
|
||||||
|
- `/api/delete`: deletes a document, requires `'write'` permission
|
||||||
|
|
||||||
|
Inside `utils/authorize.js` you can find the authorization logic for the endpoints.
|
||||||
|
In each endpoint you should configure the `INDEX` variable.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
Create an account on Vercel, then create a deployment on Elastic Cloud. If you
|
||||||
|
don't have an account on Elastic Cloud, you can create one with a free 14-day trial
|
||||||
|
of the [Elasticsearch Service](https://www.elastic.co/elasticsearch/service).
|
||||||
|
|
||||||
|
### Configure Elasticsearch
|
||||||
|
|
||||||
|
Once you have created a deployment on Elastic Cloud copy the generated Cloud Id and the credentials.
|
||||||
|
Then open `utils/prepare-elasticsearch.js` and fill your credentials. The script generates
|
||||||
|
an [Api Key](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html)
|
||||||
|
that you can use for authenticating your request. Based on the configuration of the Api Key, you will be able
|
||||||
|
to perform different operation on the specified indices or index pattern.
|
||||||
|
|
||||||
|
### Configure Vercel
|
||||||
|
|
||||||
|
Install the [Vercel CLI](https://vercel.com/docs/cli) to bootstrap the project,
|
||||||
|
or read the [quickstart](https://vercel.com/docs) documentation.
|
||||||
|
|
||||||
|
If you are using the CLI, bootstrap the project by running `vercel`. Test the project locally
|
||||||
|
with `vercel dev`, and deploy it with `vercel deploy`.
|
||||||
|
Configure the `ELASTIC_CLOUD_ID` [environment varible](https://vercel.com/docs/environment-variables) as well.
|
||||||
|
The Api Key is passed from the frontend app via a `Authorization` header as `Bearer` token and is
|
||||||
|
used to authorize the API calls to the endpoints as well.
|
||||||
|
Additional configuration, such as CORS, can be added to [`vercel.json`](https://vercel.com/docs/configuration).
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
If you are using Elasticsearch only for search purposes, such as a search box, you can create
|
||||||
|
an Api Key with `read` permissions and store it in your frontend app. Then you can send it
|
||||||
|
via `Authorization` header to the proxy and run your searches.
|
||||||
|
|
||||||
|
If you need to ingest data as well, it's more secure to have a strong authentication in your application.
|
||||||
|
For such cases, use an external authentication service, such as [Auth0](https://auth0.com/)
|
||||||
|
or [Magic Link](https://magic.link/). Then create a different Api Key with `read` and `write`
|
||||||
|
permissions for authenticated users, that will not be stored in the frontend app.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This software is licensed under the [Apache 2 license](../../LICENSE).
|
||||||
105
docs/examples/proxy/api/autocomplete.js
Normal file
105
docs/examples/proxy/api/autocomplete.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// IMPORTANT: this is not a production ready code & purely for demonstration purposes,
|
||||||
|
// we make no guarantees on it's security and stability
|
||||||
|
|
||||||
|
// NOTE: to make this endpoint work, you should create an ApiKey with 'read' permissions
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { Client } = require('@elastic/elasticsearch')
|
||||||
|
const authorize = require('../utils/authorize')
|
||||||
|
|
||||||
|
const INDEX = '<index-name>'
|
||||||
|
const client = new Client({
|
||||||
|
cloud: {
|
||||||
|
id: process.env.ELASTIC_CLOUD_ID
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = async (req, res) => {
|
||||||
|
const [err, token] = authorize(req)
|
||||||
|
if (err) {
|
||||||
|
res.status(401)
|
||||||
|
res.json(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof req.query.q !== 'string') {
|
||||||
|
res.status(400)
|
||||||
|
res.json({
|
||||||
|
error: 'Bad Request',
|
||||||
|
message: 'Missing parameter "query.q"',
|
||||||
|
statusCode: 400
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.query.q.length < 3) {
|
||||||
|
res.status(400)
|
||||||
|
res.json({
|
||||||
|
error: 'Bad Request',
|
||||||
|
message: 'The length of "query.q" should be at least 3',
|
||||||
|
statusCode: 400
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await client.search({
|
||||||
|
index: INDEX,
|
||||||
|
// You could directly send from the browser
|
||||||
|
// the Elasticsearch's query DSL, but it will
|
||||||
|
// expose you to the risk that a malicious user
|
||||||
|
// could overload your cluster by crafting
|
||||||
|
// expensive queries.
|
||||||
|
body: {
|
||||||
|
_source: ['id', 'url', 'name'], // the fields you want to show in the autocompletion
|
||||||
|
size: 0,
|
||||||
|
// https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
|
||||||
|
suggest: {
|
||||||
|
suggestions: {
|
||||||
|
prefix: req.query.q,
|
||||||
|
completion: {
|
||||||
|
field: 'suggest',
|
||||||
|
size: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `ApiKey ${token}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// It might be useful to configure http control caching headers
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
|
||||||
|
// res.setHeader('stale-while-revalidate', '30')
|
||||||
|
res.json(response.body)
|
||||||
|
} catch (err) {
|
||||||
|
res.status(err.statusCode || 500)
|
||||||
|
res.json({
|
||||||
|
error: err.name,
|
||||||
|
message: err.message,
|
||||||
|
statusCode: err.statusCode || 500
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
74
docs/examples/proxy/api/delete.js
Normal file
74
docs/examples/proxy/api/delete.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// IMPORTANT: this is not a production ready code & purely for demonstration purposes,
|
||||||
|
// we make no guarantees on it's security and stability
|
||||||
|
|
||||||
|
// NOTE: to make this endpoint work, you should create an ApiKey with 'write' permissions
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { Client } = require('@elastic/elasticsearch')
|
||||||
|
const authorize = require('../utils/authorize')
|
||||||
|
|
||||||
|
const INDEX = '<index-name>'
|
||||||
|
const client = new Client({
|
||||||
|
cloud: {
|
||||||
|
id: process.env.ELASTIC_CLOUD_ID
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = async (req, res) => {
|
||||||
|
const [err, token] = authorize(req)
|
||||||
|
if (err) {
|
||||||
|
res.status(401)
|
||||||
|
res.json(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof req.query.id !== 'string' && req.query.id.length === 0) {
|
||||||
|
res.status(400)
|
||||||
|
res.json({
|
||||||
|
error: 'Bad Request',
|
||||||
|
message: 'Missing document id',
|
||||||
|
statusCode: 400
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await client.delete({
|
||||||
|
index: INDEX,
|
||||||
|
id: req.query.id
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `ApiKey ${token}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
res.json(response.body)
|
||||||
|
} catch (err) {
|
||||||
|
res.status(err.statusCode || 500)
|
||||||
|
res.json({
|
||||||
|
error: err.name,
|
||||||
|
message: err.message,
|
||||||
|
statusCode: err.statusCode || 500
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
76
docs/examples/proxy/api/index.js
Normal file
76
docs/examples/proxy/api/index.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// IMPORTANT: this is not a production ready code & purely for demonstration purposes,
|
||||||
|
// we make no guarantees on it's security and stability
|
||||||
|
|
||||||
|
// NOTE: to make this endpoint work, you should create an ApiKey with 'write' permissions
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { Client } = require('@elastic/elasticsearch')
|
||||||
|
const authorize = require('../utils/authorize')
|
||||||
|
|
||||||
|
const INDEX = '<index-name>'
|
||||||
|
const client = new Client({
|
||||||
|
cloud: {
|
||||||
|
id: process.env.ELASTIC_CLOUD_ID
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = async (req, res) => {
|
||||||
|
const [err, token] = authorize(req)
|
||||||
|
if (err) {
|
||||||
|
res.status(401)
|
||||||
|
res.json(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof req.body !== 'object') {
|
||||||
|
res.status(400)
|
||||||
|
res.json({
|
||||||
|
error: 'Bad Request',
|
||||||
|
message: 'The document should be an object',
|
||||||
|
statusCode: 400
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await client.index({
|
||||||
|
index: INDEX,
|
||||||
|
id: req.query.id,
|
||||||
|
body: req.body
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `ApiKey ${token}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(response.statusCode)
|
||||||
|
res.json(response.body)
|
||||||
|
} catch (err) {
|
||||||
|
res.status(err.statusCode || 500)
|
||||||
|
res.json({
|
||||||
|
error: err.name,
|
||||||
|
message: err.message,
|
||||||
|
statusCode: err.statusCode || 500
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
86
docs/examples/proxy/api/search.js
Normal file
86
docs/examples/proxy/api/search.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// IMPORTANT: this is not a production ready code & purely for demonstration purposes,
|
||||||
|
// we make no guarantees on it's security and stability
|
||||||
|
|
||||||
|
// NOTE: to make this endpoint work, you should create an ApiKey with 'read' permissions
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { Client } = require('@elastic/elasticsearch')
|
||||||
|
const authorize = require('../utils/authorize')
|
||||||
|
|
||||||
|
const INDEX = '<index-name>'
|
||||||
|
const client = new Client({
|
||||||
|
cloud: {
|
||||||
|
id: process.env.ELASTIC_CLOUD_ID
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = async (req, res) => {
|
||||||
|
const [err, token] = authorize(req)
|
||||||
|
if (err) {
|
||||||
|
res.status(401)
|
||||||
|
res.json(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof req.body.text !== 'string') {
|
||||||
|
res.status(400)
|
||||||
|
res.json({
|
||||||
|
error: 'Bad Request',
|
||||||
|
message: 'Missing parameter "body.text"',
|
||||||
|
statusCode: 400
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await client.search({
|
||||||
|
index: INDEX,
|
||||||
|
// You could directly send from the browser
|
||||||
|
// the Elasticsearch's query DSL, but it will
|
||||||
|
// expose you to the risk that a malicious user
|
||||||
|
// could overload your cluster by crafting
|
||||||
|
// expensive queries.
|
||||||
|
body: {
|
||||||
|
query: {
|
||||||
|
match: { field: req.body.text }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `ApiKey ${token}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// It might be useful to configure http control caching headers
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
|
||||||
|
// res.setHeader('stale-while-revalidate', '30')
|
||||||
|
res.json(response.body)
|
||||||
|
} catch (err) {
|
||||||
|
res.status(err.statusCode || 500)
|
||||||
|
res.json({
|
||||||
|
error: err.name,
|
||||||
|
message: err.message,
|
||||||
|
statusCode: err.statusCode || 500
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
19
docs/examples/proxy/package.json
Normal file
19
docs/examples/proxy/package.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "proxy-example",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "standard"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "Tomas Della Vedova",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@elastic/elasticsearch": "^7.10.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"standard": "^16.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
54
docs/examples/proxy/utils/authorize.js
Normal file
54
docs/examples/proxy/utils/authorize.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// IMPORTANT: this is not a production ready code & purely for demonstration purposes,
|
||||||
|
// we make no guarantees on it's security and stability
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
module.exports = (req) => {
|
||||||
|
const auth = req.headers.authorization
|
||||||
|
if (typeof auth !== 'string') {
|
||||||
|
return [{
|
||||||
|
error: 'Unauthorized',
|
||||||
|
message: 'Missing authorization header',
|
||||||
|
statusCode: 401
|
||||||
|
}, null]
|
||||||
|
}
|
||||||
|
|
||||||
|
const [type, token] = req.headers.authorization.split(' ')
|
||||||
|
|
||||||
|
if (type !== 'Bearer') {
|
||||||
|
return [{
|
||||||
|
error: 'Unauthorized',
|
||||||
|
message: 'Bad authorization type',
|
||||||
|
statusCode: 401
|
||||||
|
}, null]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.length === 0) {
|
||||||
|
return [{
|
||||||
|
error: 'Unauthorized',
|
||||||
|
message: 'Bad authorization token',
|
||||||
|
statusCode: 401
|
||||||
|
}, null]
|
||||||
|
}
|
||||||
|
|
||||||
|
return [null, token]
|
||||||
|
}
|
||||||
68
docs/examples/proxy/utils/prepare-elasticsearch.js
Normal file
68
docs/examples/proxy/utils/prepare-elasticsearch.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { Client } = require('@elastic/elasticsearch')
|
||||||
|
|
||||||
|
// Your Cloud Id
|
||||||
|
const cloudId = ''
|
||||||
|
// Your admin username
|
||||||
|
const username = ''
|
||||||
|
// Your admin password
|
||||||
|
const password = ''
|
||||||
|
// The indices or index patterns you will need to access
|
||||||
|
const indexNames = ['my-index-name-or-pattern']
|
||||||
|
// see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-privileges.html#privileges-list-indices
|
||||||
|
const privileges = ['read']
|
||||||
|
|
||||||
|
async function generateApiKeys (opts) {
|
||||||
|
const client = new Client({
|
||||||
|
cloud: {
|
||||||
|
id: cloudId
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { body } = await client.security.createApiKey({
|
||||||
|
body: {
|
||||||
|
name: 'elasticsearch-proxy',
|
||||||
|
role_descriptors: {
|
||||||
|
'elasticsearch-proxy-users': {
|
||||||
|
index: [{
|
||||||
|
names: indexNames,
|
||||||
|
privileges
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return Buffer.from(`${body.id}:${body.api_key}`).toString('base64')
|
||||||
|
}
|
||||||
|
|
||||||
|
generateApiKeys()
|
||||||
|
.then(console.log)
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
13
docs/examples/proxy/vercel.json
Normal file
13
docs/examples/proxy/vercel.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"source": "/api/(.*)",
|
||||||
|
"headers": [
|
||||||
|
{ "key": "Access-Control-Allow-Credentials", "value": "true" },
|
||||||
|
{ "key": "Access-Control-Allow-Origin", "value": "*" },
|
||||||
|
{ "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
|
||||||
|
{ "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -90,4 +90,5 @@ using.
|
|||||||
|
|
||||||
WARNING: There is no official support for the browser environment. It exposes
|
WARNING: There is no official support for the browser environment. It exposes
|
||||||
your {es} instance to everyone, which could lead to security issues. We
|
your {es} instance to everyone, which could lead to security issues. We
|
||||||
recommend you to write a lightweight proxy that uses this client instead.
|
recommend you to write a lightweight proxy that uses this client instead,
|
||||||
|
you can see a proxy example https://github.com/elastic/elasticsearch-js/tree/master/docs/examples/proxy[here].
|
||||||
Reference in New Issue
Block a user