@konker.dev/neverthrow-r-middleware 0.0.2
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/LICENSE +15 -0
- package/README.md +26 -0
- package/dist/handler.d.ts +3 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +2 -0
- package/dist/handler.js.map +1 -0
- package/dist/http/HttpApiError.d.ts +16 -0
- package/dist/http/HttpApiError.d.ts.map +1 -0
- package/dist/http/HttpApiError.js +60 -0
- package/dist/http/HttpApiError.js.map +1 -0
- package/dist/http/HttpApiError.test.d.ts +2 -0
- package/dist/http/HttpApiError.test.d.ts.map +1 -0
- package/dist/http/HttpApiError.test.js +45 -0
- package/dist/http/HttpApiError.test.js.map +1 -0
- package/dist/http/Rec.d.ts +13 -0
- package/dist/http/Rec.d.ts.map +1 -0
- package/dist/http/Rec.js +2 -0
- package/dist/http/Rec.js.map +1 -0
- package/dist/http/RequestResponseHandler.d.ts +7 -0
- package/dist/http/RequestResponseHandler.d.ts.map +1 -0
- package/dist/http/RequestResponseHandler.js +2 -0
- package/dist/http/RequestResponseHandler.js.map +1 -0
- package/dist/http/RequestW.d.ts +14 -0
- package/dist/http/RequestW.d.ts.map +1 -0
- package/dist/http/RequestW.js +17 -0
- package/dist/http/RequestW.js.map +1 -0
- package/dist/http/RequestW.test.d.ts +2 -0
- package/dist/http/RequestW.test.d.ts.map +1 -0
- package/dist/http/RequestW.test.js +26 -0
- package/dist/http/RequestW.test.js.map +1 -0
- package/dist/http/ResponseW.d.ts +11 -0
- package/dist/http/ResponseW.d.ts.map +1 -0
- package/dist/http/ResponseW.js +14 -0
- package/dist/http/ResponseW.js.map +1 -0
- package/dist/http/ResponseW.test.d.ts +2 -0
- package/dist/http/ResponseW.test.d.ts.map +1 -0
- package/dist/http/ResponseW.test.js +23 -0
- package/dist/http/ResponseW.test.js.map +1 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.d.ts +14 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.d.ts.map +1 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.js +26 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.js.map +1 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.test.d.ts +2 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.test.d.ts.map +1 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.test.js +76 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.test.js.map +1 -0
- package/dist/http/contrib/base64BodyDecoder.d.ts +7 -0
- package/dist/http/contrib/base64BodyDecoder.d.ts.map +1 -0
- package/dist/http/contrib/base64BodyDecoder.js +15 -0
- package/dist/http/contrib/base64BodyDecoder.js.map +1 -0
- package/dist/http/contrib/base64BodyDecoder.test.d.ts +2 -0
- package/dist/http/contrib/base64BodyDecoder.test.d.ts.map +1 -0
- package/dist/http/contrib/base64BodyDecoder.test.js +47 -0
- package/dist/http/contrib/base64BodyDecoder.test.js.map +1 -0
- package/dist/http/contrib/basicAuthAuthenticator.d.ts +17 -0
- package/dist/http/contrib/basicAuthAuthenticator.d.ts.map +1 -0
- package/dist/http/contrib/basicAuthAuthenticator.js +30 -0
- package/dist/http/contrib/basicAuthAuthenticator.js.map +1 -0
- package/dist/http/contrib/basicAuthAuthenticator.test.d.ts +2 -0
- package/dist/http/contrib/basicAuthAuthenticator.test.d.ts.map +1 -0
- package/dist/http/contrib/basicAuthAuthenticator.test.js +64 -0
- package/dist/http/contrib/basicAuthAuthenticator.test.js.map +1 -0
- package/dist/http/contrib/basicAuthDecoder.d.ts +13 -0
- package/dist/http/contrib/basicAuthDecoder.d.ts.map +1 -0
- package/dist/http/contrib/basicAuthDecoder.js +23 -0
- package/dist/http/contrib/basicAuthDecoder.js.map +1 -0
- package/dist/http/contrib/basicAuthDecoder.test.d.ts +2 -0
- package/dist/http/contrib/basicAuthDecoder.test.d.ts.map +1 -0
- package/dist/http/contrib/basicAuthDecoder.test.js +31 -0
- package/dist/http/contrib/basicAuthDecoder.test.js.map +1 -0
- package/dist/http/contrib/bodyValidator.d.ts +11 -0
- package/dist/http/contrib/bodyValidator.d.ts.map +1 -0
- package/dist/http/contrib/bodyValidator.js +15 -0
- package/dist/http/contrib/bodyValidator.js.map +1 -0
- package/dist/http/contrib/bodyValidator.test.d.ts +2 -0
- package/dist/http/contrib/bodyValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/bodyValidator.test.js +58 -0
- package/dist/http/contrib/bodyValidator.test.js.map +1 -0
- package/dist/http/contrib/envValidator.d.ts +10 -0
- package/dist/http/contrib/envValidator.d.ts.map +1 -0
- package/dist/http/contrib/envValidator.js +12 -0
- package/dist/http/contrib/envValidator.js.map +1 -0
- package/dist/http/contrib/envValidator.test.d.ts +2 -0
- package/dist/http/contrib/envValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/envValidator.test.js +49 -0
- package/dist/http/contrib/envValidator.test.js.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.d.ts +13 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.d.ts.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.js +22 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.js.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.test.d.ts +2 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.test.d.ts.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.test.js +39 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.test.js.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.d.ts +4 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.d.ts.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.js +13 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.js.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.test.d.ts +2 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.test.d.ts.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.test.js +9 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.test.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/index.d.ts +9 -0
- package/dist/http/contrib/headersNormalizer/index.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/index.js +8 -0
- package/dist/http/contrib/headersNormalizer/index.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/index.test.d.ts +2 -0
- package/dist/http/contrib/headersNormalizer/index.test.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/index.test.js +38 -0
- package/dist/http/contrib/headersNormalizer/index.test.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/lib.d.ts +11 -0
- package/dist/http/contrib/headersNormalizer/lib.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/lib.js +64 -0
- package/dist/http/contrib/headersNormalizer/lib.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/lib.test.d.ts +2 -0
- package/dist/http/contrib/headersNormalizer/lib.test.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/lib.test.js +35 -0
- package/dist/http/contrib/headersNormalizer/lib.test.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/types.d.ts +10 -0
- package/dist/http/contrib/headersNormalizer/types.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/types.js +2 -0
- package/dist/http/contrib/headersNormalizer/types.js.map +1 -0
- package/dist/http/contrib/headersValidator.d.ts +12 -0
- package/dist/http/contrib/headersValidator.d.ts.map +1 -0
- package/dist/http/contrib/headersValidator.js +15 -0
- package/dist/http/contrib/headersValidator.js.map +1 -0
- package/dist/http/contrib/headersValidator.test.d.ts +2 -0
- package/dist/http/contrib/headersValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/headersValidator.test.js +46 -0
- package/dist/http/contrib/headersValidator.test.js.map +1 -0
- package/dist/http/contrib/helmetJsHeaders.d.ts +5 -0
- package/dist/http/contrib/helmetJsHeaders.d.ts.map +1 -0
- package/dist/http/contrib/helmetJsHeaders.js +25 -0
- package/dist/http/contrib/helmetJsHeaders.js.map +1 -0
- package/dist/http/contrib/helmetJsHeaders.test.d.ts +2 -0
- package/dist/http/contrib/helmetJsHeaders.test.d.ts.map +1 -0
- package/dist/http/contrib/helmetJsHeaders.test.js +18 -0
- package/dist/http/contrib/helmetJsHeaders.test.js.map +1 -0
- package/dist/http/contrib/honoAdapter.d.ts +16 -0
- package/dist/http/contrib/honoAdapter.d.ts.map +1 -0
- package/dist/http/contrib/honoAdapter.js +28 -0
- package/dist/http/contrib/honoAdapter.js.map +1 -0
- package/dist/http/contrib/honoAdapter.test.d.ts +2 -0
- package/dist/http/contrib/honoAdapter.test.d.ts.map +1 -0
- package/dist/http/contrib/honoAdapter.test.js +75 -0
- package/dist/http/contrib/honoAdapter.test.js.map +1 -0
- package/dist/http/contrib/identity.d.ts +4 -0
- package/dist/http/contrib/identity.d.ts.map +1 -0
- package/dist/http/contrib/identity.js +3 -0
- package/dist/http/contrib/identity.js.map +1 -0
- package/dist/http/contrib/identity.test.d.ts +2 -0
- package/dist/http/contrib/identity.test.d.ts.map +1 -0
- package/dist/http/contrib/identity.test.js +12 -0
- package/dist/http/contrib/identity.test.js.map +1 -0
- package/dist/http/contrib/index.d.ts +25 -0
- package/dist/http/contrib/index.d.ts.map +1 -0
- package/dist/http/contrib/index.js +25 -0
- package/dist/http/contrib/index.js.map +1 -0
- package/dist/http/contrib/jsonBodyParserRequest.d.ts +10 -0
- package/dist/http/contrib/jsonBodyParserRequest.d.ts.map +1 -0
- package/dist/http/contrib/jsonBodyParserRequest.js +22 -0
- package/dist/http/contrib/jsonBodyParserRequest.js.map +1 -0
- package/dist/http/contrib/jsonBodyParserRequest.test.d.ts +2 -0
- package/dist/http/contrib/jsonBodyParserRequest.test.d.ts.map +1 -0
- package/dist/http/contrib/jsonBodyParserRequest.test.js +37 -0
- package/dist/http/contrib/jsonBodyParserRequest.test.js.map +1 -0
- package/dist/http/contrib/jsonBodySerializerResponse.d.ts +9 -0
- package/dist/http/contrib/jsonBodySerializerResponse.d.ts.map +1 -0
- package/dist/http/contrib/jsonBodySerializerResponse.js +15 -0
- package/dist/http/contrib/jsonBodySerializerResponse.js.map +1 -0
- package/dist/http/contrib/jsonBodySerializerResponse.test.d.ts +2 -0
- package/dist/http/contrib/jsonBodySerializerResponse.test.d.ts.map +1 -0
- package/dist/http/contrib/jsonBodySerializerResponse.test.js +31 -0
- package/dist/http/contrib/jsonBodySerializerResponse.test.js.map +1 -0
- package/dist/http/contrib/jwtAuthenticator.d.ts +15 -0
- package/dist/http/contrib/jwtAuthenticator.d.ts.map +1 -0
- package/dist/http/contrib/jwtAuthenticator.js +28 -0
- package/dist/http/contrib/jwtAuthenticator.js.map +1 -0
- package/dist/http/contrib/jwtAuthenticator.test.d.ts +2 -0
- package/dist/http/contrib/jwtAuthenticator.test.d.ts.map +1 -0
- package/dist/http/contrib/jwtAuthenticator.test.js +88 -0
- package/dist/http/contrib/jwtAuthenticator.test.js.map +1 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.d.ts +15 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.d.ts.map +1 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.js +28 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.js.map +1 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.test.d.ts +2 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.test.d.ts.map +1 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.test.js +88 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.test.js.map +1 -0
- package/dist/http/contrib/jwtDecoder.d.ts +13 -0
- package/dist/http/contrib/jwtDecoder.d.ts.map +1 -0
- package/dist/http/contrib/jwtDecoder.js +23 -0
- package/dist/http/contrib/jwtDecoder.js.map +1 -0
- package/dist/http/contrib/jwtDecoder.test.d.ts +2 -0
- package/dist/http/contrib/jwtDecoder.test.d.ts.map +1 -0
- package/dist/http/contrib/jwtDecoder.test.js +76 -0
- package/dist/http/contrib/jwtDecoder.test.js.map +1 -0
- package/dist/http/contrib/pathParametersValidator.d.ts +12 -0
- package/dist/http/contrib/pathParametersValidator.d.ts.map +1 -0
- package/dist/http/contrib/pathParametersValidator.js +15 -0
- package/dist/http/contrib/pathParametersValidator.js.map +1 -0
- package/dist/http/contrib/pathParametersValidator.test.d.ts +2 -0
- package/dist/http/contrib/pathParametersValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/pathParametersValidator.test.js +46 -0
- package/dist/http/contrib/pathParametersValidator.test.js.map +1 -0
- package/dist/http/contrib/pathTokenAuthorizer.d.ts +13 -0
- package/dist/http/contrib/pathTokenAuthorizer.d.ts.map +1 -0
- package/dist/http/contrib/pathTokenAuthorizer.js +19 -0
- package/dist/http/contrib/pathTokenAuthorizer.js.map +1 -0
- package/dist/http/contrib/pathTokenAuthorizer.test.d.ts +2 -0
- package/dist/http/contrib/pathTokenAuthorizer.test.d.ts.map +1 -0
- package/dist/http/contrib/pathTokenAuthorizer.test.js +29 -0
- package/dist/http/contrib/pathTokenAuthorizer.test.js.map +1 -0
- package/dist/http/contrib/queryStringValidator.d.ts +12 -0
- package/dist/http/contrib/queryStringValidator.d.ts.map +1 -0
- package/dist/http/contrib/queryStringValidator.js +15 -0
- package/dist/http/contrib/queryStringValidator.js.map +1 -0
- package/dist/http/contrib/queryStringValidator.test.d.ts +2 -0
- package/dist/http/contrib/queryStringValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/queryStringValidator.test.js +46 -0
- package/dist/http/contrib/queryStringValidator.test.js.map +1 -0
- package/dist/http/contrib/requestResponseLogger.d.ts +5 -0
- package/dist/http/contrib/requestResponseLogger.d.ts.map +1 -0
- package/dist/http/contrib/requestResponseLogger.js +8 -0
- package/dist/http/contrib/requestResponseLogger.js.map +1 -0
- package/dist/http/contrib/requestResponseLogger.test.d.ts +2 -0
- package/dist/http/contrib/requestResponseLogger.test.d.ts.map +1 -0
- package/dist/http/contrib/requestResponseLogger.test.js +18 -0
- package/dist/http/contrib/requestResponseLogger.test.js.map +1 -0
- package/dist/http/contrib/responseProcessor.d.ts +8 -0
- package/dist/http/contrib/responseProcessor.d.ts.map +1 -0
- package/dist/http/contrib/responseProcessor.js +16 -0
- package/dist/http/contrib/responseProcessor.js.map +1 -0
- package/dist/http/contrib/responseProcessor.test.d.ts +2 -0
- package/dist/http/contrib/responseProcessor.test.d.ts.map +1 -0
- package/dist/http/contrib/responseProcessor.test.js +29 -0
- package/dist/http/contrib/responseProcessor.test.js.map +1 -0
- package/dist/http/contrib/standardRequestResponseAdapter.d.ts +16 -0
- package/dist/http/contrib/standardRequestResponseAdapter.d.ts.map +1 -0
- package/dist/http/contrib/standardRequestResponseAdapter.js +27 -0
- package/dist/http/contrib/standardRequestResponseAdapter.js.map +1 -0
- package/dist/http/contrib/standardRequestResponseAdapter.test.d.ts +2 -0
- package/dist/http/contrib/standardRequestResponseAdapter.test.d.ts.map +1 -0
- package/dist/http/contrib/standardRequestResponseAdapter.test.js +85 -0
- package/dist/http/contrib/standardRequestResponseAdapter.test.js.map +1 -0
- package/dist/http/contrib/trivial.d.ts +5 -0
- package/dist/http/contrib/trivial.d.ts.map +1 -0
- package/dist/http/contrib/trivial.js +9 -0
- package/dist/http/contrib/trivial.js.map +1 -0
- package/dist/http/contrib/trivial.test.d.ts +2 -0
- package/dist/http/contrib/trivial.test.d.ts.map +1 -0
- package/dist/http/contrib/trivial.test.js +14 -0
- package/dist/http/contrib/trivial.test.js.map +1 -0
- package/dist/http/index.d.ts +6 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +6 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/Logger.d.ts +23 -0
- package/dist/lib/Logger.d.ts.map +1 -0
- package/dist/lib/Logger.js +30 -0
- package/dist/lib/Logger.js.map +1 -0
- package/dist/lib/Logger.test.d.ts +2 -0
- package/dist/lib/Logger.test.d.ts.map +1 -0
- package/dist/lib/Logger.test.js +54 -0
- package/dist/lib/Logger.test.js.map +1 -0
- package/dist/lib/MiddlewareError.d.ts +10 -0
- package/dist/lib/MiddlewareError.d.ts.map +1 -0
- package/dist/lib/MiddlewareError.js +20 -0
- package/dist/lib/MiddlewareError.js.map +1 -0
- package/dist/lib/MiddlewareError.test.d.ts +2 -0
- package/dist/lib/MiddlewareError.test.d.ts.map +1 -0
- package/dist/lib/MiddlewareError.test.js +55 -0
- package/dist/lib/MiddlewareError.test.js.map +1 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +4 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/utils.d.ts +7 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +11 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/utils.test.d.ts +2 -0
- package/dist/lib/utils.test.d.ts.map +1 -0
- package/dist/lib/utils.test.js +47 -0
- package/dist/lib/utils.test.js.map +1 -0
- package/dist/test/kitchen-sink.test.d.ts +2 -0
- package/dist/test/kitchen-sink.test.d.ts.map +1 -0
- package/dist/test/kitchen-sink.test.js +76 -0
- package/dist/test/kitchen-sink.test.js.map +1 -0
- package/dist/test/round-trip.test.d.ts +2 -0
- package/dist/test/round-trip.test.d.ts.map +1 -0
- package/dist/test/round-trip.test.js +75 -0
- package/dist/test/round-trip.test.js.map +1 -0
- package/dist/test/test-common.d.ts +17 -0
- package/dist/test/test-common.d.ts.map +1 -0
- package/dist/test/test-common.js +25 -0
- package/dist/test/test-common.js.map +1 -0
- package/package.json +265 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
4
|
+
import { makeRequestW } from '../RequestW.js';
|
|
5
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
6
|
+
import { middleware as base64BodyDecoder } from './base64BodyDecoder.js';
|
|
7
|
+
describe('base64BodyDecoder', () => {
|
|
8
|
+
it('decodes base64 when the predicate matches', async () => {
|
|
9
|
+
const { logger } = recordingLogger();
|
|
10
|
+
const wrapped = base64BodyDecoder(() => true)((req) => okAsyncR({
|
|
11
|
+
...EMPTY_RESPONSE_W,
|
|
12
|
+
body: req.body,
|
|
13
|
+
}));
|
|
14
|
+
const input = makeRequestW(sampleRequestW, { body: Buffer.from('{"foo":"bar"}').toString('base64') });
|
|
15
|
+
const result = await wrapped(input)({ logger });
|
|
16
|
+
expect(result.isOk() && result.value.body).toBe('{"foo":"bar"}');
|
|
17
|
+
});
|
|
18
|
+
it('returns a MiddlewareError when decoding throws', async () => {
|
|
19
|
+
const spy = vi.spyOn(Buffer, 'from').mockImplementation(() => {
|
|
20
|
+
throw new Error('boom');
|
|
21
|
+
});
|
|
22
|
+
const { logger } = recordingLogger();
|
|
23
|
+
const wrapped = base64BodyDecoder(() => true)(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
24
|
+
const result = await wrapped(makeRequestW(sampleRequestW, { body: 'abcd' }))({ logger });
|
|
25
|
+
expect(result.isErr() && result.error.message).toBe('boom');
|
|
26
|
+
spy.mockRestore();
|
|
27
|
+
});
|
|
28
|
+
it('passes the request through unchanged when not base64 encoded', async () => {
|
|
29
|
+
const { logger } = recordingLogger();
|
|
30
|
+
const wrapped = base64BodyDecoder(() => false)((req) => okAsyncR({
|
|
31
|
+
...EMPTY_RESPONSE_W,
|
|
32
|
+
body: req.body,
|
|
33
|
+
}));
|
|
34
|
+
const result = await wrapped(makeRequestW(sampleRequestW, { body: 'plain-text' }))({ logger });
|
|
35
|
+
expect(result.isOk() && result.value.body).toBe('plain-text');
|
|
36
|
+
});
|
|
37
|
+
it('decodes an undefined body as an empty string when flagged as base64', async () => {
|
|
38
|
+
const { logger } = recordingLogger();
|
|
39
|
+
const wrapped = base64BodyDecoder(() => true)((req) => okAsyncR({
|
|
40
|
+
...EMPTY_RESPONSE_W,
|
|
41
|
+
body: req.body,
|
|
42
|
+
}));
|
|
43
|
+
const result = await wrapped(sampleRequestW)({ logger });
|
|
44
|
+
expect(result.isOk() && result.value.body).toBe('');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=base64BodyDecoder.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64BodyDecoder.test.js","sourceRoot":"","sources":["../../../src/http/contrib/base64BodyDecoder.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ValidBasicAuthCredentialSet } from '@konker.dev/neverthrow-r-auth-utils/basic-auth';
|
|
2
|
+
import type { Handler } from '../../handler.js';
|
|
3
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
4
|
+
import type { HttpApiError } from '../HttpApiError.js';
|
|
5
|
+
import type { Rec } from '../Rec.js';
|
|
6
|
+
import { type RequestW } from '../RequestW.js';
|
|
7
|
+
import type { ResponseW } from '../ResponseW.js';
|
|
8
|
+
import type { WithNormalizedInputHeaders } from './headersNormalizer/types.js';
|
|
9
|
+
export declare const TAG = "basicAuthAuthenticator";
|
|
10
|
+
export type BasicAuthAuthenticatorDeps = {
|
|
11
|
+
readonly validBasicAuthCredentialSet: ValidBasicAuthCredentialSet;
|
|
12
|
+
};
|
|
13
|
+
export type WithUserId = {
|
|
14
|
+
readonly userId: string | undefined;
|
|
15
|
+
};
|
|
16
|
+
export declare const middleware: () => <I extends Rec, O extends Rec, E, R>(wrapped: Handler<RequestW<I & WithNormalizedInputHeaders & WithUserId>, R, ResponseW<O>, E>) => Handler<RequestW<I & WithNormalizedInputHeaders>, R & WithLogger & BasicAuthAuthenticatorDeps, ResponseW<O>, E | HttpApiError>;
|
|
17
|
+
//# sourceMappingURL=basicAuthAuthenticator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basicAuthAuthenticator.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/basicAuthAuthenticator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gDAAgD,CAAC;AAKlG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E,eAAO,MAAM,GAAG,2BAA2B,CAAC;AAE5C,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,CAAC,2BAA2B,EAAE,2BAA2B,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,UAAU,SAEpB,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,0BAA0B,GAAG,UAAU,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAC1F,OAAO,CACR,QAAQ,CAAC,CAAC,GAAG,0BAA0B,CAAC,EACxC,CAAC,GAAG,UAAU,GAAG,0BAA0B,EAC3C,SAAS,CAAC,CAAC,CAAC,EACZ,CAAC,GAAG,YAAY,CAmCjB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { basicAuthDecodeHeaderValue, basicAuthVerifyCredentials } from '@konker.dev/neverthrow-r-auth-utils/basic-auth';
|
|
2
|
+
import { extractBasicAuthHeaderValue } from '@konker.dev/neverthrow-r-auth-utils/helpers';
|
|
3
|
+
import { errAsync } from 'neverthrow';
|
|
4
|
+
import { toHttpApiError } from '../HttpApiError.js';
|
|
5
|
+
import {} from '../RequestW.js';
|
|
6
|
+
export const TAG = 'basicAuthAuthenticator';
|
|
7
|
+
export const middleware = () => (wrapped) => (i) => (r) => {
|
|
8
|
+
r.logger.debug(`[${TAG}] IN`);
|
|
9
|
+
const authResult = extractBasicAuthHeaderValue(i.headers.authorization)(undefined)
|
|
10
|
+
.andThen((headerValue) => basicAuthDecodeHeaderValue(headerValue)(undefined))
|
|
11
|
+
.andThen((decoded) => basicAuthVerifyCredentials(r.validBasicAuthCredentialSet)(decoded)(undefined));
|
|
12
|
+
if (authResult.isErr()) {
|
|
13
|
+
const error = toHttpApiError(authResult.error, 401, `Invalid basic auth credentials: ${authResult.error instanceof Error ? authResult.error.message : String(authResult.error)}`);
|
|
14
|
+
r.logger.error(error);
|
|
15
|
+
return errAsync(error);
|
|
16
|
+
}
|
|
17
|
+
if (!authResult.value.verified) {
|
|
18
|
+
const error = toHttpApiError(undefined, 401, 'Invalid basic auth credentials');
|
|
19
|
+
r.logger.error(error);
|
|
20
|
+
return errAsync(error);
|
|
21
|
+
}
|
|
22
|
+
return wrapped({
|
|
23
|
+
...i,
|
|
24
|
+
userId: authResult.value.userId,
|
|
25
|
+
})(r).map((res) => {
|
|
26
|
+
r.logger.debug(`[${TAG}] OUT`);
|
|
27
|
+
return res;
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=basicAuthAuthenticator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basicAuthAuthenticator.js","sourceRoot":"","sources":["../../../src/http/contrib/basicAuthAuthenticator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AACxH,OAAO,EAAE,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAiB,MAAM,gBAAgB,CAAC;AAI/C,MAAM,CAAC,MAAM,GAAG,GAAG,wBAAwB,CAAC;AAU5C,MAAM,CAAC,MAAM,UAAU,GACrB,GAAG,EAAE,CACL,CACE,OAA2F,EAM3F,EAAE,CACJ,CAAC,CAAC,EAAE,EAAE,CACN,CAAC,CAAC,EAAE,EAAE;IACJ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IAE9B,MAAM,UAAU,GAAG,2BAA2B,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC;SAC/E,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC;SAC5E,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,0BAA0B,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAEvG,IAAI,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,cAAc,CAC1B,UAAU,CAAC,KAAK,EAChB,GAAG,EACH,mCACE,UAAU,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CACxF,EAAE,CACH,CAAC;QACF,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtB,OAAO,QAAQ,CAAiC,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,gCAAgC,CAAC,CAAC;QAC/E,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtB,OAAO,QAAQ,CAAiC,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,OAAO,CAAC;QACb,GAAG,CAAC;QACJ,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,MAAM;KACyB,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACzE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;QAC/B,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basicAuthAuthenticator.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/basicAuthAuthenticator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { errR, okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import * as helpers from '@konker.dev/neverthrow-r-auth-utils/helpers';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
5
|
+
import { makeRequestW } from '../RequestW.js';
|
|
6
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
7
|
+
import { middleware as basicAuthAuthenticator } from './basicAuthAuthenticator.js';
|
|
8
|
+
describe('basicAuthAuthenticator', () => {
|
|
9
|
+
const validAuthorization = 'Basic dXNlcjA6c2VjcmV0LTA=';
|
|
10
|
+
const invalidAuthorization = 'Basic dXNlcjA6YmFkLXNlY3JldA==';
|
|
11
|
+
it('authenticates valid credentials', async () => {
|
|
12
|
+
const { logger } = recordingLogger();
|
|
13
|
+
const wrapped = basicAuthAuthenticator()((req) => okAsyncR({
|
|
14
|
+
...EMPTY_RESPONSE_W,
|
|
15
|
+
body: req.userId,
|
|
16
|
+
}));
|
|
17
|
+
const input = makeRequestW(sampleRequestW, {
|
|
18
|
+
headers: { authorization: validAuthorization },
|
|
19
|
+
headersNormalizerRequestRaw: { Authorization: validAuthorization },
|
|
20
|
+
});
|
|
21
|
+
const result = await wrapped(input)({
|
|
22
|
+
logger,
|
|
23
|
+
validBasicAuthCredentialSet: [{ username: 'user0', passwords: ['secret-0'] }],
|
|
24
|
+
});
|
|
25
|
+
expect(result.isOk() && result.value.body).toBe('user0');
|
|
26
|
+
});
|
|
27
|
+
it('returns a 401 HttpApiError for invalid credentials', async () => {
|
|
28
|
+
const { logger } = recordingLogger();
|
|
29
|
+
const wrapped = basicAuthAuthenticator()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
30
|
+
const input = makeRequestW(sampleRequestW, {
|
|
31
|
+
headers: { authorization: invalidAuthorization },
|
|
32
|
+
headersNormalizerRequestRaw: { Authorization: invalidAuthorization },
|
|
33
|
+
});
|
|
34
|
+
const result = await wrapped(input)({
|
|
35
|
+
logger,
|
|
36
|
+
validBasicAuthCredentialSet: [{ username: 'user0', passwords: ['secret-0'] }],
|
|
37
|
+
});
|
|
38
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
39
|
+
});
|
|
40
|
+
it('returns a 401 HttpApiError when the auth header is missing', async () => {
|
|
41
|
+
const { logger } = recordingLogger();
|
|
42
|
+
const wrapped = basicAuthAuthenticator()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
43
|
+
const input = makeRequestW(sampleRequestW, {
|
|
44
|
+
headers: {},
|
|
45
|
+
headersNormalizerRequestRaw: {},
|
|
46
|
+
});
|
|
47
|
+
const result = await wrapped(input)({
|
|
48
|
+
logger,
|
|
49
|
+
validBasicAuthCredentialSet: [{ username: 'user0', passwords: ['secret-0'] }],
|
|
50
|
+
});
|
|
51
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
52
|
+
});
|
|
53
|
+
it('stringifies non-Error auth extraction failures', async () => {
|
|
54
|
+
vi.spyOn(helpers, 'extractBasicAuthHeaderValue').mockReturnValue(errR('boom'));
|
|
55
|
+
const { logger } = recordingLogger();
|
|
56
|
+
const wrapped = basicAuthAuthenticator()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
57
|
+
const result = await wrapped(makeRequestW(sampleRequestW, { headers: {}, headersNormalizerRequestRaw: {} }))({
|
|
58
|
+
logger,
|
|
59
|
+
validBasicAuthCredentialSet: [{ username: 'user0', passwords: ['secret-0'] }],
|
|
60
|
+
});
|
|
61
|
+
expect(result.isErr() && result.error.message).toContain('boom');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=basicAuthAuthenticator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basicAuthAuthenticator.test.js","sourceRoot":"","sources":["../../../src/http/contrib/basicAuthAuthenticator.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,KAAK,OAAO,MAAM,6CAA6C,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAkB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,UAAU,IAAI,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAEnF,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,MAAM,kBAAkB,GAAG,4BAA4B,CAAC;IACxD,MAAM,oBAAoB,GAAG,gCAAgC,CAAC;IAE9D,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,CAC/C,QAAQ,CAAY;YAClB,GAAG,gBAAgB;YACnB,IAAI,EAAE,GAAG,CAAC,MAAM;SACJ,CAAC,CAChB,CAAC;QACF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE;YACzC,OAAO,EAAE,EAAE,aAAa,EAAE,kBAAkB,EAAE;YAC9C,2BAA2B,EAAE,EAAE,aAAa,EAAE,kBAAkB,EAAE;SACnE,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM;YACN,2BAA2B,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;SAC9E,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QACtF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE;YACzC,OAAO,EAAE,EAAE,aAAa,EAAE,oBAAoB,EAAE;YAChD,2BAA2B,EAAE,EAAE,aAAa,EAAE,oBAAoB,EAAE;SACrE,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM;YACN,2BAA2B,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;SAC9E,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QACtF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE;YACzC,OAAO,EAAE,EAAE;YACX,2BAA2B,EAAE,EAAE;SAChC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM;YACN,2BAA2B,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;SAC9E,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC,eAAe,CAAC,IAAI,CAAM,MAAM,CAAC,CAAC,CAAC;QACpF,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QACtF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,2BAA2B,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC3G,MAAM;YACN,2BAA2B,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;SAC9E,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Handler } from '../../handler.js';
|
|
2
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
3
|
+
import type { MiddlewareError } from '../../lib/MiddlewareError.js';
|
|
4
|
+
import type { Override, Rec } from '../RequestResponseHandler.js';
|
|
5
|
+
import { type RequestW } from '../RequestW.js';
|
|
6
|
+
import type { ResponseW } from '../ResponseW.js';
|
|
7
|
+
import type { WithNormalizedInputHeaders } from './headersNormalizer/types.js';
|
|
8
|
+
export declare const TAG = "basicAuthDecoder";
|
|
9
|
+
export type WithUserId = {
|
|
10
|
+
readonly userId: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
export declare const middleware: () => <I extends Rec, O extends Rec, E, R>(wrapped: Handler<RequestW<Override<I & WithNormalizedInputHeaders, WithUserId>>, R, ResponseW<O>, E>) => Handler<RequestW<I & WithNormalizedInputHeaders>, R & WithLogger, ResponseW<O>, E | MiddlewareError>;
|
|
13
|
+
//# sourceMappingURL=basicAuthDecoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basicAuthDecoder.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/basicAuthDecoder.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E,eAAO,MAAM,GAAG,qBAAqB,CAAC;AAEtC,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,UAAU,SAEpB,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,0BAA0B,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KACnG,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,0BAA0B,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,eAAe,CAsBrG,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { basicAuthDecodeHeaderValue } from '@konker.dev/neverthrow-r-auth-utils/basic-auth';
|
|
2
|
+
import { extractBasicAuthHeaderValue } from '@konker.dev/neverthrow-r-auth-utils/helpers';
|
|
3
|
+
import { errAsync } from 'neverthrow';
|
|
4
|
+
import { toMiddlewareError } from '../../lib/MiddlewareError.js';
|
|
5
|
+
import { makeRequestW } from '../RequestW.js';
|
|
6
|
+
export const TAG = 'basicAuthDecoder';
|
|
7
|
+
export const middleware = () => (wrapped) => (i) => (r) => {
|
|
8
|
+
r.logger.debug(`[${TAG}] IN`);
|
|
9
|
+
const decoded = extractBasicAuthHeaderValue(i.headers.authorization)(undefined)
|
|
10
|
+
.andThen((headerValue) => basicAuthDecodeHeaderValue(headerValue)(undefined))
|
|
11
|
+
.mapErr(toMiddlewareError);
|
|
12
|
+
if (decoded.isErr()) {
|
|
13
|
+
r.logger.error(decoded.error);
|
|
14
|
+
return errAsync(decoded.error);
|
|
15
|
+
}
|
|
16
|
+
return wrapped(makeRequestW(i, {
|
|
17
|
+
userId: decoded.value.username,
|
|
18
|
+
}))(r).map((res) => {
|
|
19
|
+
r.logger.debug(`[${TAG}] OUT`);
|
|
20
|
+
return res;
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=basicAuthDecoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basicAuthDecoder.js","sourceRoot":"","sources":["../../../src/http/contrib/basicAuthDecoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EAAE,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAiB,MAAM,gBAAgB,CAAC;AAI7D,MAAM,CAAC,MAAM,GAAG,GAAG,kBAAkB,CAAC;AAMtC,MAAM,CAAC,MAAM,UAAU,GACrB,GAAG,EAAE,CACL,CACE,OAAoG,EACE,EAAE,CAC1G,CAAC,CAAC,EAAE,EAAE,CACN,CAAC,CAAC,EAAE,EAAE;IACJ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IAE9B,MAAM,OAAO,GAAG,2BAA2B,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC;SAC5E,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC;SAC5E,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAE7B,IAAI,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QACpB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,OAAO,CACZ,YAAY,CAAC,CAAC,EAAE;QACd,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ;KAC/B,CAAC,CACH,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;QAC/B,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basicAuthDecoder.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/basicAuthDecoder.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
4
|
+
import { makeRequestW } from '../RequestW.js';
|
|
5
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
6
|
+
import { middleware as basicAuthDecoder } from './basicAuthDecoder.js';
|
|
7
|
+
describe('basicAuthDecoder', () => {
|
|
8
|
+
const authorization = 'Basic dXNlcjA6c2VjcmV0LTA=';
|
|
9
|
+
it('extracts the userId from a valid basic auth header', async () => {
|
|
10
|
+
const { logger } = recordingLogger();
|
|
11
|
+
const wrapped = basicAuthDecoder()((req) => okAsyncR({
|
|
12
|
+
...EMPTY_RESPONSE_W,
|
|
13
|
+
body: req.userId,
|
|
14
|
+
}));
|
|
15
|
+
const input = makeRequestW(sampleRequestW, {
|
|
16
|
+
headers: { authorization },
|
|
17
|
+
headersNormalizerRequestRaw: { Authorization: authorization },
|
|
18
|
+
});
|
|
19
|
+
const result = await wrapped(input)({ logger });
|
|
20
|
+
expect(result.isOk() && result.value.body).toBe('user0');
|
|
21
|
+
});
|
|
22
|
+
it('returns a MiddlewareError when the header is missing', async () => {
|
|
23
|
+
const { logger } = recordingLogger();
|
|
24
|
+
const wrapped = basicAuthDecoder()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
25
|
+
const result = await wrapped(makeRequestW(sampleRequestW, {
|
|
26
|
+
headersNormalizerRequestRaw: {},
|
|
27
|
+
}))({ logger });
|
|
28
|
+
expect(result.isErr() && result.error.message).toBe('No token found');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=basicAuthDecoder.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basicAuthDecoder.test.js","sourceRoot":"","sources":["../../../src/http/contrib/basicAuthDecoder.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAkB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEvE,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,MAAM,aAAa,GAAG,4BAA4B,CAAC;IAEnD,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,CACzC,QAAQ,CAAY;YAClB,GAAG,gBAAgB;YACnB,IAAI,EAAE,GAAG,CAAC,MAAM;SACJ,CAAC,CAChB,CAAC;QACF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE;YACzC,OAAO,EAAE,EAAE,aAAa,EAAE;YAC1B,2BAA2B,EAAE,EAAE,aAAa,EAAE,aAAa,EAAE;SAC9D,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEhD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,YAAY,CAAC,cAAc,EAAE;YAC3B,2BAA2B,EAAE,EAAE;SAChC,CAAC,CACH,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEd,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
3
|
+
import type { MiddlewareError } from '../../lib/MiddlewareError.js';
|
|
4
|
+
import type { Override, Rec, RequestResponseHandler } from '../RequestResponseHandler.js';
|
|
5
|
+
export declare const TAG = "bodyValidator";
|
|
6
|
+
export type WithValidatedBody<V> = {
|
|
7
|
+
readonly body: V;
|
|
8
|
+
readonly bodyValidatorRaw: unknown;
|
|
9
|
+
};
|
|
10
|
+
export declare const middleware: <V>(schema: StandardSchemaV1<unknown, V>) => <I extends Rec, O extends Rec, E, R>(wrapped: RequestResponseHandler<Override<I, WithValidatedBody<V>>, R, O, E>) => RequestResponseHandler<I, R & WithLogger, O, E | MiddlewareError>;
|
|
11
|
+
//# sourceMappingURL=bodyValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyValidator.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/bodyValidator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAI1F,eAAO,MAAM,GAAG,kBAAkB,CAAC;AAEnC,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IACjC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC,CAAC;AAKF,eAAO,MAAM,UAAU,GACpB,CAAC,EAAE,QAAQ,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,MACvC,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,sBAAsB,CAAC,QAAQ,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC1E,sBAAsB,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,GAAG,eAAe,CAgBhE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { andThenAsync, mapAsync, mapErrAsync } from '@konker.dev/neverthrow-r/async';
|
|
2
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
3
|
+
import { pipe } from '@konker.dev/neverthrow-r/pipe';
|
|
4
|
+
import { andThenParseAsyncR } from '@konker.dev/neverthrow-r-schema/async';
|
|
5
|
+
import { tapLogger } from '../../lib/Logger.js';
|
|
6
|
+
import { middlewareError } from '../../lib/MiddlewareError.js';
|
|
7
|
+
import { makeRequestW } from '../RequestW.js';
|
|
8
|
+
import { makeResponseW } from '../ResponseW.js';
|
|
9
|
+
export const TAG = 'bodyValidator';
|
|
10
|
+
const toMiddlewareError = (error) => middlewareError(error.message, error.cause === undefined ? error.issues : [error.cause, ...error.issues]);
|
|
11
|
+
export const middleware = (schema) => (wrapped) => (i) => pipe(okAsyncR(i.body), tapLogger('debug', `[${TAG}] IN`), andThenParseAsyncR(schema, { message: 'Body validation failed' }), mapErrAsync(toMiddlewareError), mapAsync((validatedBody) => makeRequestW(i, {
|
|
12
|
+
body: validatedBody,
|
|
13
|
+
bodyValidatorRaw: i.body,
|
|
14
|
+
})), andThenAsync(wrapped), mapAsync((res) => makeResponseW(res)), tapLogger('debug', `[${TAG}] OUT`));
|
|
15
|
+
//# sourceMappingURL=bodyValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyValidator.js","sourceRoot":"","sources":["../../../src/http/contrib/bodyValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAK3E,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAiB,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,CAAC,MAAM,GAAG,GAAG,eAAe,CAAC;AAOnC,MAAM,iBAAiB,GAAG,CAAC,KAA4B,EAAmB,EAAE,CAC1E,eAAe,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AAE5G,MAAM,CAAC,MAAM,UAAU,GACrB,CAAI,MAAoC,EAAE,EAAE,CAC5C,CACE,OAA2E,EACR,EAAE,CACvE,CAAC,CAAc,EAAE,EAAE,CACjB,IAAI,CACF,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAChB,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,EACjC,kBAAkB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC,EACjE,WAAW,CAAC,iBAAiB,CAAC,EAC9B,QAAQ,CAAC,CAAC,aAAa,EAAE,EAAE,CACzB,YAAY,CAAC,CAAC,EAAE;IACd,IAAI,EAAE,aAAa;IACnB,gBAAgB,EAAE,CAAC,CAAC,IAAI;CACzB,CAAC,CACH,EACD,YAAY,CAAC,OAAO,CAAC,EACrB,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EACrC,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,CACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyValidator.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/bodyValidator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
5
|
+
import { makeRequestW } from '../RequestW.js';
|
|
6
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
7
|
+
import { middleware as bodyValidator } from './bodyValidator.js';
|
|
8
|
+
const positiveNumberSchema = z.number().positive();
|
|
9
|
+
describe('bodyValidator', () => {
|
|
10
|
+
it('forwards a validated body to the wrapped handler', async () => {
|
|
11
|
+
const { logger } = recordingLogger();
|
|
12
|
+
const wrapped = bodyValidator(positiveNumberSchema)((req) => okAsyncR({
|
|
13
|
+
...EMPTY_RESPONSE_W,
|
|
14
|
+
body: { received: req.body },
|
|
15
|
+
}));
|
|
16
|
+
const input = makeRequestW(sampleRequestW, { body: 42 });
|
|
17
|
+
const result = await wrapped(input)({ logger });
|
|
18
|
+
expect(result.isOk() && result.value.body).toEqual({ received: 42 });
|
|
19
|
+
});
|
|
20
|
+
it('fails with a MiddlewareError when validation fails', async () => {
|
|
21
|
+
const { logger } = recordingLogger();
|
|
22
|
+
const wrapped = bodyValidator(positiveNumberSchema)(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
23
|
+
const input = makeRequestW(sampleRequestW, { body: -1 });
|
|
24
|
+
const result = await wrapped(input)({ logger });
|
|
25
|
+
expect(result.isErr() && result.error.message).toBe('Body validation failed');
|
|
26
|
+
});
|
|
27
|
+
it('supports schemas whose validate returns a Promise', async () => {
|
|
28
|
+
const asyncSchema = z.string().transform(async (input) => input);
|
|
29
|
+
const { logger } = recordingLogger();
|
|
30
|
+
const wrapped = bodyValidator(asyncSchema)((req) => okAsyncR({
|
|
31
|
+
...EMPTY_RESPONSE_W,
|
|
32
|
+
body: { received: req.body },
|
|
33
|
+
}));
|
|
34
|
+
const input = makeRequestW(sampleRequestW, { body: 'hello' });
|
|
35
|
+
const result = await wrapped(input)({ logger });
|
|
36
|
+
expect(result.isOk() && result.value.body).toEqual({ received: 'hello' });
|
|
37
|
+
});
|
|
38
|
+
it('fails with a MiddlewareError when validation throws', async () => {
|
|
39
|
+
const cause = new Error('validator exploded');
|
|
40
|
+
const throwingSchema = {
|
|
41
|
+
'~standard': {
|
|
42
|
+
version: 1,
|
|
43
|
+
vendor: 'fixture',
|
|
44
|
+
validate: () => {
|
|
45
|
+
throw cause;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
const { logger } = recordingLogger();
|
|
50
|
+
const wrapped = bodyValidator(throwingSchema)(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
51
|
+
const result = await wrapped(sampleRequestW)({ logger });
|
|
52
|
+
expect(result.isErr() && result.error).toMatchObject({
|
|
53
|
+
message: 'Schema validation threw',
|
|
54
|
+
internal: [cause],
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=bodyValidator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyValidator.test.js","sourceRoot":"","sources":["../../../src/http/contrib/bodyValidator.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AAEjE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAiB,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAkB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,UAAU,IAAI,aAAa,EAA0B,MAAM,oBAAoB,CAAC;AAEzF,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC;AAEnD,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAwC,EAAE,EAAE,CAC/F,QAAQ,CAAY;YAClB,GAAG,gBAAgB;YACnB,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE;SAChB,CAAC,CAChB,CAAC;QACF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAK,MAAM,CAAC,KAAyC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QACjG,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QACjE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,GAAwC,EAAE,EAAE,CACtF,QAAQ,CAAY;YAClB,GAAG,gBAAgB;YACnB,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE;SAChB,CAAC,CAChB,CAAC;QACF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAK,MAAM,CAAC,KAAyC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACjH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAC9C,MAAM,cAAc,GAAsC;YACxD,WAAW,EAAE;gBACX,OAAO,EAAE,CAAC;gBACV,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,GAAG,EAAE;oBACb,MAAM,KAAK,CAAC;gBACd,CAAC;aACF;SACF,CAAC;QACF,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QAC3F,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC;YACnD,OAAO,EAAE,yBAAyB;YAClC,QAAQ,EAAE,CAAC,KAAK,CAAC;SAClB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
3
|
+
import type { MiddlewareError } from '../../lib/MiddlewareError.js';
|
|
4
|
+
import type { Override, Rec, RequestResponseHandler } from '../RequestResponseHandler.js';
|
|
5
|
+
export declare const TAG = "envValidator";
|
|
6
|
+
export type WithValidatedEnv<V> = {
|
|
7
|
+
readonly validatedEnv: V;
|
|
8
|
+
};
|
|
9
|
+
export declare const middleware: <V>(schema: StandardSchemaV1<unknown, V>) => <I extends Rec, O extends Rec, E, R>(wrapped: RequestResponseHandler<Override<I, WithValidatedEnv<V>>, R, O, E>) => RequestResponseHandler<I, R & WithLogger, O, E | MiddlewareError>;
|
|
10
|
+
//# sourceMappingURL=envValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envValidator.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/envValidator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAI1F,eAAO,MAAM,GAAG,iBAAiB,CAAC;AAElC,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;CAC1B,CAAC;AAKF,eAAO,MAAM,UAAU,GACpB,CAAC,EAAE,QAAQ,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,MACvC,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,sBAAsB,CAAC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KACzE,sBAAsB,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,GAAG,eAAe,CAWhE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { andThenAsync, mapAsync, mapErrAsync } from '@konker.dev/neverthrow-r/async';
|
|
2
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
3
|
+
import { pipe } from '@konker.dev/neverthrow-r/pipe';
|
|
4
|
+
import { andThenParseAsyncR } from '@konker.dev/neverthrow-r-schema/async';
|
|
5
|
+
import { tapLogger } from '../../lib/Logger.js';
|
|
6
|
+
import { middlewareError } from '../../lib/MiddlewareError.js';
|
|
7
|
+
import { makeRequestW } from '../RequestW.js';
|
|
8
|
+
import { makeResponseW } from '../ResponseW.js';
|
|
9
|
+
export const TAG = 'envValidator';
|
|
10
|
+
const toMiddlewareError = (error) => middlewareError(error.message, error.cause === undefined ? error.issues : [error.cause, ...error.issues]);
|
|
11
|
+
export const middleware = (schema) => (wrapped) => (i) => pipe(okAsyncR(process.env), tapLogger('debug', `[${TAG}] IN`), andThenParseAsyncR(schema, { message: 'Environment validation failed' }), mapErrAsync(toMiddlewareError), mapAsync((validatedEnv) => makeRequestW(i, { validatedEnv })), andThenAsync(wrapped), mapAsync((res) => makeResponseW(res)), tapLogger('debug', `[${TAG}] OUT`));
|
|
12
|
+
//# sourceMappingURL=envValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envValidator.js","sourceRoot":"","sources":["../../../src/http/contrib/envValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAK3E,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAiB,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,CAAC,MAAM,GAAG,GAAG,cAAc,CAAC;AAMlC,MAAM,iBAAiB,GAAG,CAAC,KAA4B,EAAmB,EAAE,CAC1E,eAAe,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AAE5G,MAAM,CAAC,MAAM,UAAU,GACrB,CAAI,MAAoC,EAAE,EAAE,CAC5C,CACE,OAA0E,EACP,EAAE,CACvE,CAAC,CAAc,EAAE,EAAE,CACjB,IAAI,CACF,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,EACrB,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,EACjC,kBAAkB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC,EACxE,WAAW,CAAC,iBAAiB,CAAC,EAC9B,QAAQ,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,EAC7D,YAAY,CAAC,OAAO,CAAC,EACrB,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EACrC,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,CACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envValidator.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/envValidator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
5
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
6
|
+
import { middleware as envValidator } from './envValidator.js';
|
|
7
|
+
describe('envValidator', () => {
|
|
8
|
+
const schema = z.object({
|
|
9
|
+
TEST_ENV_VALUE: z.literal('hello'),
|
|
10
|
+
TEST_ENV_NUM: z.coerce.number(),
|
|
11
|
+
});
|
|
12
|
+
it('injects validated env into the wrapped handler', async () => {
|
|
13
|
+
const oldEnv = process.env;
|
|
14
|
+
process.env = { ...oldEnv, TEST_ENV_VALUE: 'hello', TEST_ENV_NUM: '42' };
|
|
15
|
+
const { logger } = recordingLogger();
|
|
16
|
+
const wrapped = envValidator(schema)((req) => okAsyncR({
|
|
17
|
+
...EMPTY_RESPONSE_W,
|
|
18
|
+
body: req.validatedEnv,
|
|
19
|
+
}));
|
|
20
|
+
const result = await wrapped(sampleRequestW)({ logger });
|
|
21
|
+
process.env = oldEnv;
|
|
22
|
+
expect(result.isOk() && result.value.body).toEqual({ TEST_ENV_VALUE: 'hello', TEST_ENV_NUM: 42 });
|
|
23
|
+
});
|
|
24
|
+
it('returns a MiddlewareError on invalid env', async () => {
|
|
25
|
+
const oldEnv = process.env;
|
|
26
|
+
process.env = { TEST_ENV_VALUE: 'bad' };
|
|
27
|
+
const { logger } = recordingLogger();
|
|
28
|
+
const wrapped = envValidator(schema)((_req) => okAsyncR(EMPTY_RESPONSE_W));
|
|
29
|
+
const result = await wrapped(sampleRequestW)({ logger });
|
|
30
|
+
process.env = oldEnv;
|
|
31
|
+
expect(result.isErr() && result.error.message).toBe('Environment validation failed');
|
|
32
|
+
});
|
|
33
|
+
it('keeps a thrown validator cause in internal details', async () => {
|
|
34
|
+
const schema = {
|
|
35
|
+
'~standard': {
|
|
36
|
+
version: 1,
|
|
37
|
+
vendor: 'fixture',
|
|
38
|
+
validate: () => {
|
|
39
|
+
throw new Error('validator exploded');
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
const { logger } = recordingLogger();
|
|
44
|
+
const wrapped = envValidator(schema)(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
45
|
+
const result = await wrapped(sampleRequestW)({ logger });
|
|
46
|
+
expect(result.isErr() && result.error.internal?.length).toBeGreaterThan(0);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=envValidator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envValidator.test.js","sourceRoot":"","sources":["../../../src/http/contrib/envValidator.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Handler } from '../../../handler.js';
|
|
2
|
+
import type { WithLogger } from '../../../lib/Logger.js';
|
|
3
|
+
import { HttpApiError } from '../../HttpApiError.js';
|
|
4
|
+
import type { Rec } from '../../Rec.js';
|
|
5
|
+
import type { RequestW } from '../../RequestW.js';
|
|
6
|
+
import type { ResponseW } from '../../ResponseW.js';
|
|
7
|
+
export declare const TAG = "headerSignatureAuthorizer";
|
|
8
|
+
export type HeaderSignatureAuthorizerDeps = {
|
|
9
|
+
readonly secret: string;
|
|
10
|
+
readonly signatureHeaderName: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const middleware: () => <I extends Rec, O extends Rec, E, R>(wrapped: Handler<RequestW<I>, R, ResponseW<O>, E>) => Handler<RequestW<I>, R & WithLogger & HeaderSignatureAuthorizerDeps, ResponseW<O>, E | HttpApiError>;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/http/contrib/headerSignatureAuthorizer/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,eAAO,MAAM,GAAG,8BAA8B,CAAC;AAE/C,MAAM,MAAM,6BAA6B,GAAG;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC,CAAC;AAEF,eAAO,MAAM,UAAU,SAEpB,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAChD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,6BAA6B,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,YAAY,CAqBrG,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { errAsync } from 'neverthrow';
|
|
2
|
+
import { HttpApiError } from '../../HttpApiError.js';
|
|
3
|
+
import { validateHeaderSignature } from './lib.js';
|
|
4
|
+
export const TAG = 'headerSignatureAuthorizer';
|
|
5
|
+
export const middleware = () => (wrapped) => (i) => (r) => {
|
|
6
|
+
r.logger.debug(`[${TAG}] IN`);
|
|
7
|
+
const gateResult = validateHeaderSignature(i.headers[r.signatureHeaderName], i.body, r.secret)(undefined);
|
|
8
|
+
if (gateResult.isErr()) {
|
|
9
|
+
r.logger.error(gateResult.error);
|
|
10
|
+
return errAsync(gateResult.error);
|
|
11
|
+
}
|
|
12
|
+
if (!gateResult.value) {
|
|
13
|
+
const error = new HttpApiError({ statusCode: 401, message: 'Invalid signature' });
|
|
14
|
+
r.logger.error(error);
|
|
15
|
+
return errAsync(error);
|
|
16
|
+
}
|
|
17
|
+
return wrapped(i)(r).map((res) => {
|
|
18
|
+
r.logger.debug(`[${TAG}] OUT`);
|
|
19
|
+
return res;
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/http/contrib/headerSignatureAuthorizer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAIrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,CAAC,MAAM,GAAG,GAAG,2BAA2B,CAAC;AAO/C,MAAM,CAAC,MAAM,UAAU,GACrB,GAAG,EAAE,CACL,CACE,OAAiD,EACqD,EAAE,CAC1G,CAAC,CAAC,EAAE,EAAE,CACN,CAAC,CAAC,EAAE,EAAE;IACJ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IAE9B,MAAM,UAAU,GAAG,uBAAuB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1G,IAAI,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC;QACvB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACjC,OAAO,QAAQ,CAA6B,UAAU,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAClF,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtB,OAAO,QAAQ,CAA6B,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC/B,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;QAC/B,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../../src/http/contrib/headerSignatureAuthorizer/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { errR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { recordingLogger, sampleRequestW } from '../../../test/test-common.js';
|
|
5
|
+
import { HttpApiError } from '../../HttpApiError.js';
|
|
6
|
+
import { makeRequestW } from '../../RequestW.js';
|
|
7
|
+
import { EMPTY_RESPONSE_W } from '../../ResponseW.js';
|
|
8
|
+
import { middleware as headerSignatureAuthorizer } from './index.js';
|
|
9
|
+
import * as lib from './lib.js';
|
|
10
|
+
describe('headerSignatureAuthorizer', () => {
|
|
11
|
+
it('authorizes when the signature matches the body', async () => {
|
|
12
|
+
const { logger } = recordingLogger();
|
|
13
|
+
const wrapped = headerSignatureAuthorizer()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
14
|
+
const input = makeRequestW(sampleRequestW, {
|
|
15
|
+
body: 'payload',
|
|
16
|
+
headers: { 'x-signature': 'b82fcb791acec57859b989b430a826488ce2e479fdf92326bd0a2e8375a42ba4' },
|
|
17
|
+
});
|
|
18
|
+
const result = await wrapped(input)({ logger, secret: 'secret', signatureHeaderName: 'x-signature' });
|
|
19
|
+
expect(result.isOk()).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it('returns a 401 HttpApiError when the signature is invalid', async () => {
|
|
22
|
+
const { logger } = recordingLogger();
|
|
23
|
+
const wrapped = headerSignatureAuthorizer()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
24
|
+
const input = makeRequestW(sampleRequestW, {
|
|
25
|
+
body: 'payload',
|
|
26
|
+
headers: { 'x-signature': 'bad' },
|
|
27
|
+
});
|
|
28
|
+
const result = await wrapped(input)({ logger, secret: 'secret', signatureHeaderName: 'x-signature' });
|
|
29
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
30
|
+
});
|
|
31
|
+
it('returns the validation error when signature calculation fails', async () => {
|
|
32
|
+
vi.spyOn(lib, 'validateHeaderSignature').mockReturnValue(errR(new HttpApiError({ statusCode: 500, message: 'boom' })));
|
|
33
|
+
const { logger } = recordingLogger();
|
|
34
|
+
const wrapped = headerSignatureAuthorizer()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
35
|
+
const result = await wrapped(sampleRequestW)({ logger, secret: 'secret', signatureHeaderName: 'x-signature' });
|
|
36
|
+
expect(result.isErr() && result.error.message).toBe('boom');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=index.test.js.map
|