@backstage/plugin-search-backend 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @backstage/plugin-search-backend
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a41fbfe739: Search result location filtering
8
+
9
+ This change introduces a filter for search results based on their location protocol. The intention is to filter out unsafe or
10
+ malicious values before they can be consumed by the frontend. By default locations must be http/https URLs (or paths).
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+ - @backstage/backend-common@0.10.0
16
+
3
17
  ## 0.2.8
4
18
 
5
19
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -8,15 +8,27 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
8
8
 
9
9
  var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
10
10
 
11
+ const allowedLocationProtocols = ["http:", "https:"];
11
12
  async function createRouter(options) {
12
13
  const { engine, logger } = options;
14
+ const filterResultSet = ({ results, ...resultSet }) => ({
15
+ ...resultSet,
16
+ results: results.filter((result) => {
17
+ const protocol = new URL(result.document.location, "https://example.com").protocol;
18
+ const isAllowed = allowedLocationProtocols.includes(protocol);
19
+ if (!isAllowed) {
20
+ logger.info(`Rejected search result for "${result.document.title}" as location protocol "${protocol}" is unsafe`);
21
+ }
22
+ return isAllowed;
23
+ })
24
+ });
13
25
  const router = Router__default["default"]();
14
26
  router.get("/query", async (req, res) => {
15
27
  const { term, filters = {}, types, pageCursor } = req.query;
16
28
  logger.info(`Search request received: term="${term}", filters=${JSON.stringify(filters)}, types=${types ? types.join(",") : ""}, pageCursor=${pageCursor != null ? pageCursor : ""}`);
17
29
  try {
18
- const results = await (engine == null ? void 0 : engine.query(req.query));
19
- res.send(results);
30
+ const resultSet = await (engine == null ? void 0 : engine.query(req.query));
31
+ res.send(filterResultSet(resultSet));
20
32
  } catch (err) {
21
33
  throw new Error(`There was a problem performing the search query. ${err}`);
22
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Logger } from 'winston';\nimport { SearchQuery, SearchResultSet } from '@backstage/search-common';\nimport { SearchEngine } from '@backstage/plugin-search-backend-node';\n\nexport type RouterOptions = {\n engine: SearchEngine;\n logger: Logger;\n};\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { engine, logger } = options;\n const router = Router();\n router.get(\n '/query',\n async (\n req: express.Request<any, unknown, unknown, SearchQuery>,\n res: express.Response<SearchResultSet>,\n ) => {\n const { term, filters = {}, types, pageCursor } = req.query;\n logger.info(\n `Search request received: term=\"${term}\", filters=${JSON.stringify(\n filters,\n )}, types=${types ? types.join(',') : ''}, pageCursor=${\n pageCursor ?? ''\n }`,\n );\n\n try {\n const results = await engine?.query(req.query);\n res.send(results);\n } catch (err) {\n throw new Error(\n `There was a problem performing the search query. ${err}`,\n );\n }\n },\n );\n\n return router;\n}\n"],"names":["Router"],"mappings":";;;;;;;;;;4BA4BE,SACyB;AACzB,QAAM,EAAE,QAAQ,WAAW;AAC3B,QAAM,SAASA;AACf,SAAO,IACL,UACA,OACE,KACA,QACG;AACH,UAAM,EAAE,MAAM,UAAU,IAAI,OAAO,eAAe,IAAI;AACtD,WAAO,KACL,kCAAkC,kBAAkB,KAAK,UACvD,mBACU,QAAQ,MAAM,KAAK,OAAO,kBACpC,kCAAc;AAIlB,QAAI;AACF,YAAM,UAAU,wCAAc,MAAM,IAAI;AACxC,UAAI,KAAK;AAAA,aACF,KAAP;AACA,YAAM,IAAI,MACR,oDAAoD;AAAA;AAAA;AAM5D,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Logger } from 'winston';\nimport { SearchQuery, SearchResultSet } from '@backstage/search-common';\nimport { SearchEngine } from '@backstage/plugin-search-backend-node';\n\nexport type RouterOptions = {\n engine: SearchEngine;\n logger: Logger;\n};\n\nconst allowedLocationProtocols = ['http:', 'https:'];\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { engine, logger } = options;\n\n const filterResultSet = ({ results, ...resultSet }: SearchResultSet) => ({\n ...resultSet,\n results: results.filter(result => {\n const protocol = new URL(result.document.location, 'https://example.com')\n .protocol;\n const isAllowed = allowedLocationProtocols.includes(protocol);\n if (!isAllowed) {\n logger.info(\n `Rejected search result for \"${result.document.title}\" as location protocol \"${protocol}\" is unsafe`,\n );\n }\n return isAllowed;\n }),\n });\n\n const router = Router();\n router.get(\n '/query',\n async (\n req: express.Request<any, unknown, unknown, SearchQuery>,\n res: express.Response<SearchResultSet>,\n ) => {\n const { term, filters = {}, types, pageCursor } = req.query;\n logger.info(\n `Search request received: term=\"${term}\", filters=${JSON.stringify(\n filters,\n )}, types=${types ? types.join(',') : ''}, pageCursor=${\n pageCursor ?? ''\n }`,\n );\n\n try {\n const resultSet = await engine?.query(req.query);\n res.send(filterResultSet(resultSet));\n } catch (err) {\n throw new Error(\n `There was a problem performing the search query. ${err}`,\n );\n }\n },\n );\n\n return router;\n}\n"],"names":["Router"],"mappings":";;;;;;;;;;AA2BA,MAAM,2BAA2B,CAAC,SAAS;4BAGzC,SACyB;AACzB,QAAM,EAAE,QAAQ,WAAW;AAE3B,QAAM,kBAAkB,CAAC,EAAE,YAAY;AAAkC,OACpE;AAAA,IACH,SAAS,QAAQ,OAAO,YAAU;AAChC,YAAM,WAAW,IAAI,IAAI,OAAO,SAAS,UAAU,uBAChD;AACH,YAAM,YAAY,yBAAyB,SAAS;AACpD,UAAI,CAAC,WAAW;AACd,eAAO,KACL,+BAA+B,OAAO,SAAS,gCAAgC;AAAA;AAGnF,aAAO;AAAA;AAAA;AAIX,QAAM,SAASA;AACf,SAAO,IACL,UACA,OACE,KACA,QACG;AACH,UAAM,EAAE,MAAM,UAAU,IAAI,OAAO,eAAe,IAAI;AACtD,WAAO,KACL,kCAAkC,kBAAkB,KAAK,UACvD,mBACU,QAAQ,MAAM,KAAK,OAAO,kBACpC,kCAAc;AAIlB,QAAI;AACF,YAAM,YAAY,wCAAc,MAAM,IAAI;AAC1C,UAAI,KAAK,gBAAgB;AAAA,aAClB,KAAP;AACA,YAAM,IAAI,MACR,oDAAoD;AAAA;AAAA;AAM5D,SAAO;AAAA;;;;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@backstage/plugin-search-backend",
3
3
  "description": "The Backstage backend plugin that provides your backstage app with search",
4
- "version": "0.2.8",
4
+ "version": "0.3.0",
5
5
  "main": "dist/index.cjs.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "Apache-2.0",
@@ -20,7 +20,7 @@
20
20
  "clean": "backstage-cli clean"
21
21
  },
22
22
  "dependencies": {
23
- "@backstage/backend-common": "^0.9.13",
23
+ "@backstage/backend-common": "^0.10.0",
24
24
  "@backstage/plugin-search-backend-node": "^0.4.2",
25
25
  "@backstage/search-common": "^0.2.0",
26
26
  "@types/express": "^4.17.6",
@@ -30,12 +30,12 @@
30
30
  "yn": "^4.0.0"
31
31
  },
32
32
  "devDependencies": {
33
- "@backstage/cli": "^0.10.1",
33
+ "@backstage/cli": "^0.10.3",
34
34
  "@types/supertest": "^2.0.8",
35
35
  "supertest": "^6.1.3"
36
36
  },
37
37
  "files": [
38
38
  "dist"
39
39
  ],
40
- "gitHead": "562be0b43016294e27af3ad024191bb86b13b1c1"
40
+ "gitHead": "b315430f9dfcfa19ab0dd90f5b4ac6904938fba7"
41
41
  }