@backstage/backend-defaults 0.17.1 → 0.17.2-next.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 +14 -0
- package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js.map +1 -1
- package/dist/lib/rateLimitMiddleware.cjs.js +2 -4
- package/dist/lib/rateLimitMiddleware.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +1 -1
- package/dist/urlReader.d.ts +2 -2
- package/package.json +17 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @backstage/backend-defaults
|
|
2
2
|
|
|
3
|
+
## 0.17.2-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a07e6a3: Updated `AzureBlobStorageUrlReader` to reference the correctly-named `AzureBlobStorageIntegration` type from `@backstage/integration`. The previously-used `AzureBlobStorageIntergation` is now an alias for the new type and remains a valid argument to the constructor.
|
|
8
|
+
- def82d4: Fixed the built-in rate limiter throwing a validation error and refusing to start when `backend.rateLimit` is enabled. Requests are now keyed using the address normalization helper from `express-rate-limit`, which is required by newer versions of that library and ensures IPv6 clients are grouped by their address block rather than by individual address.
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/integration@2.0.3-next.0
|
|
11
|
+
- @backstage/plugin-auth-node@0.7.2-next.0
|
|
12
|
+
- @backstage/backend-app-api@1.7.1-next.0
|
|
13
|
+
- @backstage/plugin-permission-node@0.11.1-next.0
|
|
14
|
+
- @backstage/backend-plugin-api@1.9.2-next.0
|
|
15
|
+
- @backstage/plugin-events-node@0.4.23-next.0
|
|
16
|
+
|
|
3
17
|
## 0.17.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AzureBlobStorageUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2024 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 {\n BlobDownloadOptions,\n BlobServiceClient,\n ContainerClient,\n StorageSharedKeyCredential,\n} from '@azure/storage-blob';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport { toError, ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { Readable } from 'node:stream';\nimport { relative } from 'node:path/posix';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport {\n AzureBlobStorageIntergation,\n AzureCredentialsManager,\n DefaultAzureCredentialsManager,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\n\nexport function parseUrl(url: string): { path: string; container: string } {\n const parsedUrl = new URL(url);\n const pathSegments = parsedUrl.pathname.split('/').filter(Boolean);\n\n if (pathSegments.length < 1) {\n throw new Error(`Invalid Azure Blob Storage URL format: ${url}`);\n }\n\n // First segment is the container name, rest is the blob path\n const container = pathSegments[0];\n const path = pathSegments.slice(1).join('/');\n\n return { path, container };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure storage accounts urls.\n *\n * @public\n */\nexport class AzureBlobStorageUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n\n const credsManager =\n DefaultAzureCredentialsManager.fromIntegrations(integrations);\n\n return integrations.azureBlobStorage.list().map(integrationConfig => {\n const reader = new AzureBlobStorageUrlReader(\n credsManager,\n integrationConfig,\n {\n treeResponseFactory,\n },\n );\n\n const predicate = (url: URL) =>\n url.host.endsWith(\n `${integrationConfig.config.accountName}.${integrationConfig.config.host}`,\n );\n return { reader, predicate };\n });\n };\n\n // private readonly blobServiceClient: BlobServiceClient;\n\n private readonly credsManager: AzureCredentialsManager;\n private readonly integration: AzureBlobStorageIntergation;\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n };\n\n constructor(\n credsManager: AzureCredentialsManager,\n integration: AzureBlobStorageIntergation,\n deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {\n this.credsManager = credsManager;\n this.integration = integration;\n this.deps = deps;\n }\n\n private async createContainerClient(\n containerName: string,\n ): Promise<ContainerClient> {\n const accountName = this.integration.config.accountName; // Use the account name from the integration config\n const accountKey = this.integration.config.accountKey; // Get the account key if it exists\n\n if (accountKey && accountName) {\n const creds = new StorageSharedKeyCredential(accountName, accountKey);\n const blobServiceClient = new BlobServiceClient(\n `https://${accountName}.${this.integration.config.host}`,\n creds,\n );\n return blobServiceClient.getContainerClient(containerName);\n }\n // Use the credentials manager to get the correct credentials\n const credential = await this.credsManager.getCredentials(\n accountName as string,\n );\n\n let blobServiceClientUrl: string;\n\n if (this.integration.config.endpoint) {\n if (this.integration.config.sasToken) {\n blobServiceClientUrl = `${this.integration.config.endpoint}?${this.integration.config.sasToken}`;\n } else {\n blobServiceClientUrl = `${this.integration.config.endpoint}`;\n }\n } else {\n blobServiceClientUrl = `https://${this.integration.config.accountName}.${this.integration.config.host}`;\n }\n\n const blobServiceClient = new BlobServiceClient(\n blobServiceClientUrl,\n credential,\n );\n return blobServiceClient.getContainerClient(containerName);\n }\n\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const { etag, lastModifiedAfter } = options ?? {};\n\n try {\n const { path, container } = parseUrl(url);\n\n const containerClient = await this.createContainerClient(container);\n const blobClient = containerClient.getBlobClient(path);\n\n const getBlobOptions: BlobDownloadOptions = {\n abortSignal: options?.signal,\n conditions: {\n ...(etag && { ifNoneMatch: etag }),\n ...(lastModifiedAfter && { ifModifiedSince: lastModifiedAfter }),\n },\n };\n\n const downloadBlockBlobResponse = await blobClient.download(\n 0,\n undefined,\n getBlobOptions,\n );\n\n return ReadUrlResponseFactory.fromReadable(\n downloadBlockBlobResponse.readableStreamBody as Readable,\n {\n etag: downloadBlockBlobResponse.etag,\n lastModifiedAt: downloadBlockBlobResponse.lastModified,\n },\n );\n } catch (e) {\n if (e.statusCode === 304) {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError(\n 'Could not retrieve file from Azure Blob Storage',\n e,\n );\n }\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n try {\n const { path, container } = parseUrl(url);\n\n const containerClient = await this.createContainerClient(container);\n const blobs = containerClient.listBlobsFlat({ prefix: path });\n\n const responses = [];\n\n for await (const blob of blobs) {\n const blobClient = containerClient.getBlobClient(blob.name);\n\n const downloadBlockBlobResponse = await blobClient.download(\n undefined,\n undefined,\n { abortSignal: options?.signal },\n );\n\n responses.push({\n data: Readable.from(\n downloadBlockBlobResponse.readableStreamBody as Readable,\n ),\n path: relative(path, blob.name),\n lastModifiedAt: blob.properties.lastModified,\n });\n }\n\n return this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n throw new ForwardedError(\n 'Could not retrieve file tree from Azure Blob Storage',\n e,\n );\n }\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseUrl(url);\n\n if (path.match(/[*?]/)) {\n throw new Error(\n 'Glob search pattern not implemented for AzureBlobStorageUrlReader',\n );\n }\n\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (e) {\n throw toError(e);\n }\n }\n\n toString() {\n const accountName = this.integration.config.accountName;\n const accountKey = this.integration.config.accountKey;\n return `azureBlobStorage{accountName=${accountName},authed=${Boolean(\n accountKey,\n )}}`;\n }\n}\n"],"names":["ScmIntegrations","DefaultAzureCredentialsManager","StorageSharedKeyCredential","blobServiceClient","BlobServiceClient","ReadUrlResponseFactory","NotModifiedError","ForwardedError","Readable","relative","toError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AzureBlobStorageUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2024 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 {\n BlobDownloadOptions,\n BlobServiceClient,\n ContainerClient,\n StorageSharedKeyCredential,\n} from '@azure/storage-blob';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport { toError, ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { Readable } from 'node:stream';\nimport { relative } from 'node:path/posix';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport {\n AzureBlobStorageIntegration,\n AzureCredentialsManager,\n DefaultAzureCredentialsManager,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\n\nexport function parseUrl(url: string): { path: string; container: string } {\n const parsedUrl = new URL(url);\n const pathSegments = parsedUrl.pathname.split('/').filter(Boolean);\n\n if (pathSegments.length < 1) {\n throw new Error(`Invalid Azure Blob Storage URL format: ${url}`);\n }\n\n // First segment is the container name, rest is the blob path\n const container = pathSegments[0];\n const path = pathSegments.slice(1).join('/');\n\n return { path, container };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure storage accounts urls.\n *\n * @public\n */\nexport class AzureBlobStorageUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n\n const credsManager =\n DefaultAzureCredentialsManager.fromIntegrations(integrations);\n\n return integrations.azureBlobStorage.list().map(integrationConfig => {\n const reader = new AzureBlobStorageUrlReader(\n credsManager,\n integrationConfig,\n {\n treeResponseFactory,\n },\n );\n\n const predicate = (url: URL) =>\n url.host.endsWith(\n `${integrationConfig.config.accountName}.${integrationConfig.config.host}`,\n );\n return { reader, predicate };\n });\n };\n\n // private readonly blobServiceClient: BlobServiceClient;\n\n private readonly credsManager: AzureCredentialsManager;\n private readonly integration: AzureBlobStorageIntegration;\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n };\n\n constructor(\n credsManager: AzureCredentialsManager,\n integration: AzureBlobStorageIntegration,\n deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {\n this.credsManager = credsManager;\n this.integration = integration;\n this.deps = deps;\n }\n\n private async createContainerClient(\n containerName: string,\n ): Promise<ContainerClient> {\n const accountName = this.integration.config.accountName; // Use the account name from the integration config\n const accountKey = this.integration.config.accountKey; // Get the account key if it exists\n\n if (accountKey && accountName) {\n const creds = new StorageSharedKeyCredential(accountName, accountKey);\n const blobServiceClient = new BlobServiceClient(\n `https://${accountName}.${this.integration.config.host}`,\n creds,\n );\n return blobServiceClient.getContainerClient(containerName);\n }\n // Use the credentials manager to get the correct credentials\n const credential = await this.credsManager.getCredentials(\n accountName as string,\n );\n\n let blobServiceClientUrl: string;\n\n if (this.integration.config.endpoint) {\n if (this.integration.config.sasToken) {\n blobServiceClientUrl = `${this.integration.config.endpoint}?${this.integration.config.sasToken}`;\n } else {\n blobServiceClientUrl = `${this.integration.config.endpoint}`;\n }\n } else {\n blobServiceClientUrl = `https://${this.integration.config.accountName}.${this.integration.config.host}`;\n }\n\n const blobServiceClient = new BlobServiceClient(\n blobServiceClientUrl,\n credential,\n );\n return blobServiceClient.getContainerClient(containerName);\n }\n\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const { etag, lastModifiedAfter } = options ?? {};\n\n try {\n const { path, container } = parseUrl(url);\n\n const containerClient = await this.createContainerClient(container);\n const blobClient = containerClient.getBlobClient(path);\n\n const getBlobOptions: BlobDownloadOptions = {\n abortSignal: options?.signal,\n conditions: {\n ...(etag && { ifNoneMatch: etag }),\n ...(lastModifiedAfter && { ifModifiedSince: lastModifiedAfter }),\n },\n };\n\n const downloadBlockBlobResponse = await blobClient.download(\n 0,\n undefined,\n getBlobOptions,\n );\n\n return ReadUrlResponseFactory.fromReadable(\n downloadBlockBlobResponse.readableStreamBody as Readable,\n {\n etag: downloadBlockBlobResponse.etag,\n lastModifiedAt: downloadBlockBlobResponse.lastModified,\n },\n );\n } catch (e) {\n if (e.statusCode === 304) {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError(\n 'Could not retrieve file from Azure Blob Storage',\n e,\n );\n }\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n try {\n const { path, container } = parseUrl(url);\n\n const containerClient = await this.createContainerClient(container);\n const blobs = containerClient.listBlobsFlat({ prefix: path });\n\n const responses = [];\n\n for await (const blob of blobs) {\n const blobClient = containerClient.getBlobClient(blob.name);\n\n const downloadBlockBlobResponse = await blobClient.download(\n undefined,\n undefined,\n { abortSignal: options?.signal },\n );\n\n responses.push({\n data: Readable.from(\n downloadBlockBlobResponse.readableStreamBody as Readable,\n ),\n path: relative(path, blob.name),\n lastModifiedAt: blob.properties.lastModified,\n });\n }\n\n return this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n throw new ForwardedError(\n 'Could not retrieve file tree from Azure Blob Storage',\n e,\n );\n }\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseUrl(url);\n\n if (path.match(/[*?]/)) {\n throw new Error(\n 'Glob search pattern not implemented for AzureBlobStorageUrlReader',\n );\n }\n\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (e) {\n throw toError(e);\n }\n }\n\n toString() {\n const accountName = this.integration.config.accountName;\n const accountKey = this.integration.config.accountKey;\n return `azureBlobStorage{accountName=${accountName},authed=${Boolean(\n accountKey,\n )}}`;\n }\n}\n"],"names":["ScmIntegrations","DefaultAzureCredentialsManager","StorageSharedKeyCredential","blobServiceClient","BlobServiceClient","ReadUrlResponseFactory","NotModifiedError","ForwardedError","Readable","relative","toError"],"mappings":"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"}
|
|
@@ -41,10 +41,8 @@ const rateLimitMiddleware = (options) => {
|
|
|
41
41
|
skipFailedRequests,
|
|
42
42
|
passOnStoreError,
|
|
43
43
|
keyGenerator(req, _res) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return req.ip;
|
|
44
|
+
const ip = req.ip ?? req.socket.remoteAddress;
|
|
45
|
+
return ip ? expressRateLimit.ipKeyGenerator(ip) : "";
|
|
48
46
|
},
|
|
49
47
|
skip: (req, _res) => {
|
|
50
48
|
return Boolean(req.ip && ipAllowList.includes(req.ip)) || Boolean(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rateLimitMiddleware.cjs.js","sources":["../../src/lib/rateLimitMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport { RequestHandler } from 'express';\nimport { rateLimit, Store } from 'express-rate-limit';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\n\nexport const rateLimitMiddleware = (options: {\n store?: Store;\n config?: Config;\n}): RequestHandler => {\n const { store, config } = options;\n let windowMs: number = 60000;\n if (config && config.has('window')) {\n const windowDuration = readDurationFromConfig(config, {\n key: 'window',\n });\n windowMs = durationToMilliseconds(windowDuration);\n }\n const limit = config?.getOptionalNumber('incomingRequestLimit');\n const ipAllowList = config?.getOptionalStringArray('ipAllowList') ?? [\n '127.0.0.1',\n '0:0:0:0:0:0:0:1',\n '::1',\n ];\n const skipSuccessfulRequests = config?.getOptionalBoolean(\n 'skipSuccessfulRequests',\n );\n const skipFailedRequests = config?.getOptionalBoolean('skipFailedRequests');\n const passOnStoreError = config?.getOptionalBoolean('passOnStoreError');\n\n return rateLimit({\n windowMs,\n limit,\n skipSuccessfulRequests,\n message: {\n error: {\n name: 'Error',\n message: `Too many requests, please try again later`,\n },\n response: {\n statusCode: 429,\n },\n },\n statusCode: 429,\n skipFailedRequests,\n passOnStoreError: passOnStoreError,\n keyGenerator(req, _res): string {\n
|
|
1
|
+
{"version":3,"file":"rateLimitMiddleware.cjs.js","sources":["../../src/lib/rateLimitMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport { RequestHandler } from 'express';\nimport { ipKeyGenerator, rateLimit, Store } from 'express-rate-limit';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\n\nexport const rateLimitMiddleware = (options: {\n store?: Store;\n config?: Config;\n}): RequestHandler => {\n const { store, config } = options;\n let windowMs: number = 60000;\n if (config && config.has('window')) {\n const windowDuration = readDurationFromConfig(config, {\n key: 'window',\n });\n windowMs = durationToMilliseconds(windowDuration);\n }\n const limit = config?.getOptionalNumber('incomingRequestLimit');\n const ipAllowList = config?.getOptionalStringArray('ipAllowList') ?? [\n '127.0.0.1',\n '0:0:0:0:0:0:0:1',\n '::1',\n ];\n const skipSuccessfulRequests = config?.getOptionalBoolean(\n 'skipSuccessfulRequests',\n );\n const skipFailedRequests = config?.getOptionalBoolean('skipFailedRequests');\n const passOnStoreError = config?.getOptionalBoolean('passOnStoreError');\n\n return rateLimit({\n windowMs,\n limit,\n skipSuccessfulRequests,\n message: {\n error: {\n name: 'Error',\n message: `Too many requests, please try again later`,\n },\n response: {\n statusCode: 429,\n },\n },\n statusCode: 429,\n skipFailedRequests,\n passOnStoreError: passOnStoreError,\n keyGenerator(req, _res): string {\n // `ipKeyGenerator` normalizes the address before it is used as a rate\n // limiting key. This is required by express-rate-limit 8.x, which rejects\n // key generators that reference `req.ip` directly, as a naive IPv6 key\n // would let clients trivially bypass the limit by rotating addresses\n // within their allotted block.\n const ip = req.ip ?? req.socket.remoteAddress;\n return ip ? ipKeyGenerator(ip) : '';\n },\n skip: (req, _res) => {\n return (\n Boolean(req.ip && ipAllowList.includes(req.ip)) ||\n Boolean(\n req.socket.remoteAddress &&\n ipAllowList.includes(req.socket.remoteAddress),\n )\n );\n },\n validate: {\n trustProxy: false,\n },\n store,\n });\n};\n"],"names":["config","readDurationFromConfig","durationToMilliseconds","rateLimit","ipKeyGenerator"],"mappings":";;;;;;AAoBO,MAAM,mBAAA,GAAsB,CAAC,OAAA,KAGd;AACpB,EAAA,MAAM,EAAE,KAAA,UAAOA,QAAA,EAAO,GAAI,OAAA;AAC1B,EAAA,IAAI,QAAA,GAAmB,GAAA;AACvB,EAAA,IAAIA,QAAA,IAAUA,QAAA,CAAO,GAAA,CAAI,QAAQ,CAAA,EAAG;AAClC,IAAA,MAAM,cAAA,GAAiBC,8BAAuBD,QAAA,EAAQ;AAAA,MACpD,GAAA,EAAK;AAAA,KACN,CAAA;AACD,IAAA,QAAA,GAAWE,6BAAuB,cAAc,CAAA;AAAA,EAClD;AACA,EAAA,MAAM,KAAA,GAAQF,QAAA,EAAQ,iBAAA,CAAkB,sBAAsB,CAAA;AAC9D,EAAA,MAAM,WAAA,GAAcA,QAAA,EAAQ,sBAAA,CAAuB,aAAa,CAAA,IAAK;AAAA,IACnE,WAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,yBAAyBA,QAAA,EAAQ,kBAAA;AAAA,IACrC;AAAA,GACF;AACA,EAAA,MAAM,kBAAA,GAAqBA,QAAA,EAAQ,kBAAA,CAAmB,oBAAoB,CAAA;AAC1E,EAAA,MAAM,gBAAA,GAAmBA,QAAA,EAAQ,kBAAA,CAAmB,kBAAkB,CAAA;AAEtE,EAAA,OAAOG,0BAAA,CAAU;AAAA,IACf,QAAA;AAAA,IACA,KAAA;AAAA,IACA,sBAAA;AAAA,IACA,OAAA,EAAS;AAAA,MACP,KAAA,EAAO;AAAA,QACL,IAAA,EAAM,OAAA;AAAA,QACN,OAAA,EAAS,CAAA,yCAAA;AAAA,OACX;AAAA,MACA,QAAA,EAAU;AAAA,QACR,UAAA,EAAY;AAAA;AACd,KACF;AAAA,IACA,UAAA,EAAY,GAAA;AAAA,IACZ,kBAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAA,CAAa,KAAK,IAAA,EAAc;AAM9B,MAAA,MAAM,EAAA,GAAK,GAAA,CAAI,EAAA,IAAM,GAAA,CAAI,MAAA,CAAO,aAAA;AAChC,MAAA,OAAO,EAAA,GAAKC,+BAAA,CAAe,EAAE,CAAA,GAAI,EAAA;AAAA,IACnC,CAAA;AAAA,IACA,IAAA,EAAM,CAAC,GAAA,EAAK,IAAA,KAAS;AACnB,MAAA,OACE,OAAA,CAAQ,IAAI,EAAA,IAAM,WAAA,CAAY,SAAS,GAAA,CAAI,EAAE,CAAC,CAAA,IAC9C,OAAA;AAAA,QACE,IAAI,MAAA,CAAO,aAAA,IACT,YAAY,QAAA,CAAS,GAAA,CAAI,OAAO,aAAa;AAAA,OACjD;AAAA,IAEJ,CAAA;AAAA,IACA,QAAA,EAAU;AAAA,MACR,UAAA,EAAY;AAAA,KACd;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
|
package/dist/package.json.cjs.js
CHANGED
package/dist/urlReader.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
2
|
import { RootConfigService, LoggerService, UrlReaderServiceReadTreeResponse, UrlReaderService, UrlReaderServiceReadUrlOptions, UrlReaderServiceReadUrlResponse, UrlReaderServiceReadTreeOptions, UrlReaderServiceSearchOptions, UrlReaderServiceSearchResponse } from '@backstage/backend-plugin-api';
|
|
3
|
-
import { AzureIntegration, AzureDevOpsCredentialsProvider, BitbucketCloudIntegration, BitbucketServerIntegration, GerritIntegration, GithubIntegration, GithubCredentialsProvider, GitLabIntegration, GiteaIntegration, HarnessIntegration, AwsS3Integration, AzureCredentialsManager,
|
|
3
|
+
import { AzureIntegration, AzureDevOpsCredentialsProvider, BitbucketCloudIntegration, BitbucketServerIntegration, GerritIntegration, GithubIntegration, GithubCredentialsProvider, GitLabIntegration, GiteaIntegration, HarnessIntegration, AwsS3Integration, AzureCredentialsManager, AzureBlobStorageIntegration } from '@backstage/integration';
|
|
4
4
|
import { Readable } from 'node:stream';
|
|
5
5
|
import { AwsCredentialsManager } from '@backstage/integration-aws-node';
|
|
6
6
|
import { Config } from '@backstage/config';
|
|
@@ -334,7 +334,7 @@ declare class AzureBlobStorageUrlReader implements UrlReaderService {
|
|
|
334
334
|
private readonly credsManager;
|
|
335
335
|
private readonly integration;
|
|
336
336
|
private readonly deps;
|
|
337
|
-
constructor(credsManager: AzureCredentialsManager, integration:
|
|
337
|
+
constructor(credsManager: AzureCredentialsManager, integration: AzureBlobStorageIntegration, deps: {
|
|
338
338
|
treeResponseFactory: ReadTreeResponseFactory;
|
|
339
339
|
});
|
|
340
340
|
private createContainerClient;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/backend-defaults",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2-next.0",
|
|
4
4
|
"description": "Backend defaults used by Backstage backend apps",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -218,20 +218,20 @@
|
|
|
218
218
|
"@aws-sdk/types": "^3.347.0",
|
|
219
219
|
"@azure/identity": "^4.0.0",
|
|
220
220
|
"@azure/storage-blob": "^12.5.0",
|
|
221
|
-
"@backstage/backend-app-api": "
|
|
222
|
-
"@backstage/backend-dev-utils": "
|
|
223
|
-
"@backstage/backend-plugin-api": "
|
|
224
|
-
"@backstage/cli-node": "
|
|
225
|
-
"@backstage/config": "
|
|
226
|
-
"@backstage/config-loader": "
|
|
227
|
-
"@backstage/errors": "
|
|
228
|
-
"@backstage/integration": "
|
|
229
|
-
"@backstage/integration-aws-node": "
|
|
230
|
-
"@backstage/plugin-auth-node": "
|
|
231
|
-
"@backstage/plugin-events-node": "
|
|
232
|
-
"@backstage/plugin-permission-common": "
|
|
233
|
-
"@backstage/plugin-permission-node": "
|
|
234
|
-
"@backstage/types": "
|
|
221
|
+
"@backstage/backend-app-api": "1.7.1-next.0",
|
|
222
|
+
"@backstage/backend-dev-utils": "0.1.7",
|
|
223
|
+
"@backstage/backend-plugin-api": "1.9.2-next.0",
|
|
224
|
+
"@backstage/cli-node": "0.3.2",
|
|
225
|
+
"@backstage/config": "1.3.8",
|
|
226
|
+
"@backstage/config-loader": "1.10.11",
|
|
227
|
+
"@backstage/errors": "1.3.1",
|
|
228
|
+
"@backstage/integration": "2.0.3-next.0",
|
|
229
|
+
"@backstage/integration-aws-node": "0.2.0",
|
|
230
|
+
"@backstage/plugin-auth-node": "0.7.2-next.0",
|
|
231
|
+
"@backstage/plugin-events-node": "0.4.23-next.0",
|
|
232
|
+
"@backstage/plugin-permission-common": "0.9.9",
|
|
233
|
+
"@backstage/plugin-permission-node": "0.11.1-next.0",
|
|
234
|
+
"@backstage/types": "1.2.2",
|
|
235
235
|
"@google-cloud/storage": "^7.0.0",
|
|
236
236
|
"@keyv/memcache": "^2.0.1",
|
|
237
237
|
"@keyv/redis": "^4.0.1",
|
|
@@ -286,8 +286,8 @@
|
|
|
286
286
|
},
|
|
287
287
|
"devDependencies": {
|
|
288
288
|
"@aws-sdk/util-stream-node": "^3.350.0",
|
|
289
|
-
"@backstage/backend-test-utils": "
|
|
290
|
-
"@backstage/cli": "
|
|
289
|
+
"@backstage/backend-test-utils": "1.11.4-next.0",
|
|
290
|
+
"@backstage/cli": "0.36.3-next.0",
|
|
291
291
|
"@google-cloud/cloud-sql-connector": "^1.4.0",
|
|
292
292
|
"@types/archiver": "^7.0.0",
|
|
293
293
|
"@types/base64-stream": "^1.0.2",
|