@c15t/backend 2.0.0-rc.1 → 2.0.0-rc.10
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/README.md +3 -3
- package/dist/302.js +473 -0
- package/dist/583.js +540 -0
- package/dist/915.js +1771 -0
- package/dist/cache.cjs +5 -5
- package/dist/cache.js +4 -415
- package/dist/core.cjs +1356 -120
- package/dist/core.js +163 -1981
- package/dist/db/adapters/drizzle.cjs +1 -1
- package/dist/db/adapters/drizzle.js +1 -2
- package/dist/db/adapters/kysely.cjs +1 -1
- package/dist/db/adapters/kysely.js +1 -2
- package/dist/db/adapters/mongo.cjs +1 -1
- package/dist/db/adapters/mongo.js +1 -2
- package/dist/db/adapters/prisma.cjs +1 -1
- package/dist/db/adapters/prisma.js +1 -2
- package/dist/db/adapters/typeorm.cjs +1 -1
- package/dist/db/adapters/typeorm.js +1 -2
- package/dist/db/adapters.cjs +1 -1
- package/dist/db/migrator.cjs +1 -1
- package/dist/db/schema.cjs +43 -3
- package/dist/db/schema.js +35 -4
- package/dist/define-config.cjs +1 -1
- package/dist/edge.cjs +1106 -0
- package/dist/edge.js +190 -0
- package/dist/router.cjs +885 -123
- package/dist/router.js +1 -1507
- package/dist/{types.cjs → types/index.cjs} +1 -1
- package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
- package/{dist → dist-types}/cache/gvl-resolver.d.ts +0 -1
- package/{dist → dist-types}/cache/index.d.ts +0 -1
- package/{dist → dist-types}/cache/keys.d.ts +0 -1
- package/{dist → dist-types}/cache/types.d.ts +0 -1
- package/{dist → dist-types}/core.d.ts +8 -1
- package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
- package/dist-types/db/registry/consent-policy.d.ts +78 -0
- package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
- package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
- package/dist-types/db/registry/index.d.ts +118 -0
- package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
- package/{dist → dist-types}/db/registry/subject.d.ts +0 -2
- package/{dist → dist-types}/db/registry/types.d.ts +1 -1
- package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
- package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +1 -2
- package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -32
- package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -2
- package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +3 -3
- package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +7 -2
- package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +455 -28
- package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
- package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +1 -3
- package/{dist → dist-types}/db/schema/index.d.ts +908 -86
- package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
- package/dist-types/define-config.d.ts +17 -0
- package/dist-types/edge/index.d.ts +5 -0
- package/dist-types/edge/init-handler.d.ts +40 -0
- package/dist-types/edge/resolve-consent.d.ts +80 -0
- package/dist-types/edge/types.d.ts +13 -0
- package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
- package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
- package/{dist → dist-types}/handlers/init/index.d.ts +2 -3
- package/dist-types/handlers/init/policy.d.ts +26 -0
- package/dist-types/handlers/init/resolve-init.d.ts +44 -0
- package/dist-types/handlers/init/translations.d.ts +48 -0
- package/dist-types/handlers/legal-document/current.handler.d.ts +11 -0
- package/dist-types/handlers/legal-document/snapshot.d.ts +39 -0
- package/dist-types/handlers/policy/snapshot.d.ts +99 -0
- package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
- package/{dist → dist-types}/handlers/subject/get.handler.d.ts +3 -2
- package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/subject/list.handler.d.ts +3 -2
- package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -2
- package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
- package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +3 -1
- package/{dist → dist-types}/init.d.ts +4 -7
- package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
- package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
- package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
- package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
- package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +0 -1
- package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
- package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
- package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
- package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
- package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
- package/dist-types/policies/builder.d.ts +127 -0
- package/dist-types/policies/defaults.d.ts +2 -0
- package/dist-types/policies/matchers.d.ts +3 -0
- package/{dist → dist-types}/router.d.ts +0 -1
- package/{dist → dist-types}/routes/consent.d.ts +0 -1
- package/{dist → dist-types}/routes/index.d.ts +1 -1
- package/{dist → dist-types}/routes/init.d.ts +0 -1
- package/dist-types/routes/legal-document.d.ts +7 -0
- package/{dist → dist-types}/routes/status.d.ts +0 -1
- package/{dist → dist-types}/routes/subject.d.ts +0 -1
- package/{dist → dist-types}/types/api.d.ts +0 -1
- package/dist-types/types/index.d.ts +464 -0
- package/dist-types/utils/background.d.ts +6 -0
- package/{dist → dist-types}/utils/create-telemetry-options.d.ts +1 -2
- package/{dist → dist-types}/utils/env.d.ts +0 -1
- package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
- package/{dist → dist-types}/utils/instrumentation.d.ts +2 -3
- package/{dist → dist-types}/utils/logger.d.ts +0 -1
- package/{dist → dist-types}/utils/metrics.d.ts +0 -1
- package/dist-types/version.d.ts +1 -0
- package/docs/README.md +49 -0
- package/docs/api/configuration.md +208 -0
- package/docs/api/endpoints.md +211 -0
- package/docs/guides/caching.md +85 -0
- package/docs/guides/database-setup.md +128 -0
- package/docs/guides/edge-deployment.md +251 -0
- package/docs/guides/framework-integration.md +142 -0
- package/docs/guides/iab-tcf.md +89 -0
- package/docs/guides/observability.md +96 -0
- package/docs/guides/policy-packs.md +396 -0
- package/docs/quickstart.md +129 -0
- package/package.json +51 -37
- package/.turbo/turbo-build.log +0 -49
- package/CHANGELOG.md +0 -99
- package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
- package/dist/cache/adapters/index.d.ts.map +0 -1
- package/dist/cache/adapters/memory.d.ts.map +0 -1
- package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
- package/dist/cache/gvl-resolver.d.ts.map +0 -1
- package/dist/cache/index.d.ts.map +0 -1
- package/dist/cache/keys.d.ts.map +0 -1
- package/dist/cache/types.d.ts.map +0 -1
- package/dist/core.d.ts.map +0 -1
- package/dist/db/adapters/drizzle.d.ts +0 -2
- package/dist/db/adapters/drizzle.d.ts.map +0 -1
- package/dist/db/adapters/index.d.ts +0 -2
- package/dist/db/adapters/index.d.ts.map +0 -1
- package/dist/db/adapters/kysely.d.ts +0 -2
- package/dist/db/adapters/kysely.d.ts.map +0 -1
- package/dist/db/adapters/mongo.d.ts +0 -2
- package/dist/db/adapters/mongo.d.ts.map +0 -1
- package/dist/db/adapters/prisma.d.ts +0 -2
- package/dist/db/adapters/prisma.d.ts.map +0 -1
- package/dist/db/adapters/typeorm.d.ts +0 -2
- package/dist/db/adapters/typeorm.d.ts.map +0 -1
- package/dist/db/migrator/index.d.ts.map +0 -1
- package/dist/db/registry/consent-policy.d.ts +0 -23
- package/dist/db/registry/consent-policy.d.ts.map +0 -1
- package/dist/db/registry/consent-purpose.d.ts.map +0 -1
- package/dist/db/registry/domain.d.ts.map +0 -1
- package/dist/db/registry/index.d.ts +0 -57
- package/dist/db/registry/index.d.ts.map +0 -1
- package/dist/db/registry/subject.d.ts.map +0 -1
- package/dist/db/registry/types.d.ts.map +0 -1
- package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
- package/dist/db/registry/utils.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
- package/dist/db/schema/index.d.ts.map +0 -1
- package/dist/db/tenant-scope.d.ts.map +0 -1
- package/dist/define-config.d.ts +0 -5
- package/dist/define-config.d.ts.map +0 -1
- package/dist/handlers/consent/check.handler.d.ts.map +0 -1
- package/dist/handlers/consent/index.d.ts +0 -12
- package/dist/handlers/consent/index.d.ts.map +0 -1
- package/dist/handlers/init/geo.d.ts.map +0 -1
- package/dist/handlers/init/index.d.ts.map +0 -1
- package/dist/handlers/init/translations.d.ts +0 -28
- package/dist/handlers/init/translations.d.ts.map +0 -1
- package/dist/handlers/status/index.d.ts +0 -7
- package/dist/handlers/status/index.d.ts.map +0 -1
- package/dist/handlers/status/status.handler.d.ts.map +0 -1
- package/dist/handlers/subject/get.handler.d.ts.map +0 -1
- package/dist/handlers/subject/index.d.ts +0 -10
- package/dist/handlers/subject/index.d.ts.map +0 -1
- package/dist/handlers/subject/list.handler.d.ts.map +0 -1
- package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
- package/dist/handlers/subject/post.handler.d.ts.map +0 -1
- package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
- package/dist/init.d.ts.map +0 -1
- package/dist/middleware/auth/index.d.ts.map +0 -1
- package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
- package/dist/middleware/cors/cors.d.ts.map +0 -1
- package/dist/middleware/cors/index.d.ts +0 -30
- package/dist/middleware/cors/index.d.ts.map +0 -1
- package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
- package/dist/middleware/cors/process-cors.d.ts.map +0 -1
- package/dist/middleware/openapi/config.d.ts.map +0 -1
- package/dist/middleware/openapi/handlers.d.ts.map +0 -1
- package/dist/middleware/openapi/index.d.ts +0 -12
- package/dist/middleware/openapi/index.d.ts.map +0 -1
- package/dist/middleware/process-ip/index.d.ts.map +0 -1
- package/dist/router.d.ts.map +0 -1
- package/dist/routes/consent.d.ts.map +0 -1
- package/dist/routes/index.d.ts.map +0 -1
- package/dist/routes/init.d.ts.map +0 -1
- package/dist/routes/status.d.ts.map +0 -1
- package/dist/routes/subject.d.ts.map +0 -1
- package/dist/types/api.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -255
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/create-telemetry-options.d.ts.map +0 -1
- package/dist/utils/env.d.ts.map +0 -1
- package/dist/utils/extract-error-message.d.ts.map +0 -1
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/instrumentation.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/metrics.d.ts.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.d.ts.map +0 -1
- package/knip.json +0 -31
- package/rslib.config.ts +0 -93
- package/src/cache/adapters/cloudflare-kv.ts +0 -71
- package/src/cache/adapters/index.ts +0 -22
- package/src/cache/adapters/memory.ts +0 -111
- package/src/cache/adapters/upstash-redis.ts +0 -113
- package/src/cache/gvl-resolver.ts +0 -289
- package/src/cache/index.ts +0 -34
- package/src/cache/keys.ts +0 -68
- package/src/cache/types.ts +0 -66
- package/src/core.ts +0 -368
- package/src/db/migrator/index.ts +0 -80
- package/src/db/registry/consent-policy.test.ts +0 -451
- package/src/db/registry/consent-policy.ts +0 -82
- package/src/db/registry/consent-purpose.test.ts +0 -428
- package/src/db/registry/consent-purpose.ts +0 -61
- package/src/db/registry/domain.test.ts +0 -445
- package/src/db/registry/domain.ts +0 -91
- package/src/db/registry/index.ts +0 -14
- package/src/db/registry/subject.test.ts +0 -388
- package/src/db/registry/subject.ts +0 -129
- package/src/db/registry/types.ts +0 -10
- package/src/db/registry/utils/generate-id.test.ts +0 -216
- package/src/db/registry/utils/generate-id.ts +0 -133
- package/src/db/registry/utils.ts +0 -133
- package/src/db/schema/1.0.0/audit-log.ts +0 -15
- package/src/db/schema/1.0.0/consent-policy.ts +0 -14
- package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
- package/src/db/schema/1.0.0/consent-record.ts +0 -10
- package/src/db/schema/1.0.0/consent.ts +0 -20
- package/src/db/schema/1.0.0/domain.ts +0 -12
- package/src/db/schema/1.0.0/index.ts +0 -48
- package/src/db/schema/1.0.0/subject.ts +0 -12
- package/src/db/schema/2.0.0/audit-log.ts +0 -18
- package/src/db/schema/2.0.0/consent-policy.ts +0 -28
- package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
- package/src/db/schema/2.0.0/consent.ts +0 -26
- package/src/db/schema/2.0.0/domain.ts +0 -12
- package/src/db/schema/2.0.0/index.ts +0 -47
- package/src/db/schema/2.0.0/subject.ts +0 -14
- package/src/db/schema/index.ts +0 -15
- package/src/db/tenant-scope.test.ts +0 -750
- package/src/db/tenant-scope.ts +0 -103
- package/src/define-config.ts +0 -5
- package/src/handlers/consent/check.handler.ts +0 -126
- package/src/handlers/init/geo.test.ts +0 -317
- package/src/handlers/init/geo.ts +0 -195
- package/src/handlers/init/index.test.ts +0 -205
- package/src/handlers/init/index.ts +0 -114
- package/src/handlers/init/translations.test.ts +0 -121
- package/src/handlers/init/translations.ts +0 -72
- package/src/handlers/status/status.handler.test.ts +0 -155
- package/src/handlers/status/status.handler.ts +0 -51
- package/src/handlers/subject/get.handler.ts +0 -93
- package/src/handlers/subject/list.handler.ts +0 -93
- package/src/handlers/subject/patch.handler.ts +0 -122
- package/src/handlers/subject/post.handler.test.ts +0 -294
- package/src/handlers/subject/post.handler.ts +0 -254
- package/src/handlers/utils/consent-enrichment.test.ts +0 -380
- package/src/handlers/utils/consent-enrichment.ts +0 -218
- package/src/init.test.ts +0 -126
- package/src/init.ts +0 -87
- package/src/middleware/auth/index.ts +0 -11
- package/src/middleware/auth/validate-api-key.test.ts +0 -86
- package/src/middleware/auth/validate-api-key.ts +0 -107
- package/src/middleware/cors/cors.test.ts +0 -135
- package/src/middleware/cors/cors.ts +0 -186
- package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
- package/src/middleware/cors/is-origin-trusted.ts +0 -130
- package/src/middleware/cors/process-cors.ts +0 -91
- package/src/middleware/openapi/config.ts +0 -29
- package/src/middleware/openapi/handlers.ts +0 -34
- package/src/middleware/process-ip/index.test.ts +0 -195
- package/src/middleware/process-ip/index.ts +0 -199
- package/src/router.ts +0 -15
- package/src/routes/consent.ts +0 -52
- package/src/routes/index.ts +0 -10
- package/src/routes/init.ts +0 -102
- package/src/routes/status.ts +0 -46
- package/src/routes/subject.ts +0 -152
- package/src/types/api.ts +0 -48
- package/src/types/index.ts +0 -288
- package/src/utils/create-telemetry-options.test.ts +0 -302
- package/src/utils/create-telemetry-options.ts +0 -229
- package/src/utils/env.ts +0 -84
- package/src/utils/extract-error-message.ts +0 -21
- package/src/utils/instrumentation.test.ts +0 -185
- package/src/utils/instrumentation.ts +0 -196
- package/src/utils/logger.ts +0 -41
- package/src/utils/metrics.test.ts +0 -323
- package/src/utils/metrics.ts +0 -402
- package/src/utils/telemetry-pii.test.ts +0 -325
- package/src/version.ts +0 -2
- package/tsconfig.json +0 -11
- package/vitest.config.ts +0 -28
- /package/dist/{types.js → types/index.js} +0 -0
- /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
- /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
- /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
- /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
- /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
- /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
- /package/{src/utils/index.ts → dist-types/utils/index.d.ts} +0 -0
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { isOriginTrusted } from './is-origin-trusted';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Test suite for CORS utility functions
|
|
6
|
-
*/
|
|
7
|
-
describe('CORS utilities', () => {
|
|
8
|
-
describe('isOriginTrusted', () => {
|
|
9
|
-
it('should match exact origins', () => {
|
|
10
|
-
const trustedDomains = ['example.com'];
|
|
11
|
-
expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(true);
|
|
12
|
-
expect(isOriginTrusted('https://other.com', trustedDomains)).toBe(false);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('should handle origins with trailing slashes', () => {
|
|
16
|
-
const trustedDomains = ['example.com'];
|
|
17
|
-
expect(isOriginTrusted('https://example.com/', trustedDomains)).toBe(
|
|
18
|
-
true
|
|
19
|
-
);
|
|
20
|
-
expect(isOriginTrusted('https://example.com//', trustedDomains)).toBe(
|
|
21
|
-
true
|
|
22
|
-
);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should handle origins with paths', () => {
|
|
26
|
-
const trustedDomains = ['example.com'];
|
|
27
|
-
expect(isOriginTrusted('https://example.com/path', trustedDomains)).toBe(
|
|
28
|
-
true
|
|
29
|
-
);
|
|
30
|
-
expect(
|
|
31
|
-
isOriginTrusted('https://example.com/path/subpath', trustedDomains)
|
|
32
|
-
).toBe(true);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should handle multiple trusted domains', () => {
|
|
36
|
-
const trustedDomains = ['example.com', 'test.com'];
|
|
37
|
-
expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(true);
|
|
38
|
-
expect(isOriginTrusted('https://test.com', trustedDomains)).toBe(true);
|
|
39
|
-
expect(isOriginTrusted('https://other.com', trustedDomains)).toBe(false);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should handle wildcard subdomains', () => {
|
|
43
|
-
const trustedDomains = ['*.example.com'];
|
|
44
|
-
expect(isOriginTrusted('https://sub.example.com', trustedDomains)).toBe(
|
|
45
|
-
true
|
|
46
|
-
);
|
|
47
|
-
expect(
|
|
48
|
-
isOriginTrusted('https://other.sub.example.com', trustedDomains)
|
|
49
|
-
).toBe(true);
|
|
50
|
-
expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(
|
|
51
|
-
false
|
|
52
|
-
);
|
|
53
|
-
expect(isOriginTrusted('https://other.com', trustedDomains)).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should handle different protocols', () => {
|
|
57
|
-
const trustedDomains = ['example.com'];
|
|
58
|
-
expect(isOriginTrusted('http://example.com', trustedDomains)).toBe(true);
|
|
59
|
-
expect(isOriginTrusted('wss://example.com', trustedDomains)).toBe(true);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should handle ports in origins', () => {
|
|
63
|
-
const trustedDomains = ['example.com'];
|
|
64
|
-
expect(isOriginTrusted('https://example.com:3000', trustedDomains)).toBe(
|
|
65
|
-
true
|
|
66
|
-
);
|
|
67
|
-
expect(isOriginTrusted('http://example.com:8080', trustedDomains)).toBe(
|
|
68
|
-
true
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should handle empty trusted domains array', () => {
|
|
73
|
-
const trustedDomains: string[] = [];
|
|
74
|
-
expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(
|
|
75
|
-
false
|
|
76
|
-
);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should handle invalid origin formats', () => {
|
|
80
|
-
const trustedDomains = ['example.com'];
|
|
81
|
-
expect(isOriginTrusted('invalid-url', trustedDomains)).toBe(false);
|
|
82
|
-
expect(isOriginTrusted('', trustedDomains)).toBe(false);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should handle case sensitivity', () => {
|
|
86
|
-
const trustedDomains = ['EXAMPLE.com'];
|
|
87
|
-
expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(true);
|
|
88
|
-
expect(isOriginTrusted('https://EXAMPLE.COM', trustedDomains)).toBe(true);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should handle subdomain levels with wildcards', () => {
|
|
92
|
-
const trustedDomains = ['*.example.com'];
|
|
93
|
-
expect(isOriginTrusted('https://a.b.example.com', trustedDomains)).toBe(
|
|
94
|
-
true
|
|
95
|
-
);
|
|
96
|
-
expect(isOriginTrusted('https://a.example.com', trustedDomains)).toBe(
|
|
97
|
-
true
|
|
98
|
-
);
|
|
99
|
-
expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(
|
|
100
|
-
false
|
|
101
|
-
);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe('multiple subdomain levels', () => {
|
|
105
|
-
it('should match base domain when explicitly listed', () => {
|
|
106
|
-
const trustedDomains = ['my-site.com'];
|
|
107
|
-
expect(isOriginTrusted('https://my-site.com', trustedDomains)).toBe(
|
|
108
|
-
true
|
|
109
|
-
);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should match single-level subdomain with wildcard pattern', () => {
|
|
113
|
-
const trustedDomains = ['*.my-site.com'];
|
|
114
|
-
expect(
|
|
115
|
-
isOriginTrusted('https://foobar.my-site.com', trustedDomains)
|
|
116
|
-
).toBe(true);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should match multi-level subdomain with wildcard pattern', () => {
|
|
120
|
-
const trustedDomains = ['*.my-site.com'];
|
|
121
|
-
expect(
|
|
122
|
-
isOriginTrusted('https://foo.bar.my-site.com', trustedDomains)
|
|
123
|
-
).toBe(true);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should match three-level subdomain with wildcard pattern', () => {
|
|
127
|
-
const trustedDomains = ['*.my-site.com'];
|
|
128
|
-
expect(
|
|
129
|
-
isOriginTrusted('https://a.b.c.my-site.com', trustedDomains)
|
|
130
|
-
).toBe(true);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should not match base domain with wildcard pattern', () => {
|
|
134
|
-
const trustedDomains = ['*.my-site.com'];
|
|
135
|
-
expect(isOriginTrusted('https://my-site.com', trustedDomains)).toBe(
|
|
136
|
-
false
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('should not match similar domain that is not a subdomain', () => {
|
|
141
|
-
const trustedDomains = ['*.my-site.com'];
|
|
142
|
-
expect(isOriginTrusted('https://notmy-site.com', trustedDomains)).toBe(
|
|
143
|
-
false
|
|
144
|
-
);
|
|
145
|
-
expect(
|
|
146
|
-
isOriginTrusted('https://foobar-my-site.com', trustedDomains)
|
|
147
|
-
).toBe(false);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should match both base domain and subdomains when both are configured', () => {
|
|
151
|
-
const trustedDomains = ['my-site.com', '*.my-site.com'];
|
|
152
|
-
expect(isOriginTrusted('https://my-site.com', trustedDomains)).toBe(
|
|
153
|
-
true
|
|
154
|
-
);
|
|
155
|
-
expect(
|
|
156
|
-
isOriginTrusted('https://foobar.my-site.com', trustedDomains)
|
|
157
|
-
).toBe(true);
|
|
158
|
-
expect(
|
|
159
|
-
isOriginTrusted('https://foo.bar.my-site.com', trustedDomains)
|
|
160
|
-
).toBe(true);
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
});
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Origin validation utilities for CORS security
|
|
3
|
-
*
|
|
4
|
-
* @packageDocumentation
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Logger } from '@c15t/logger';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Regular expression to strip protocol, trailing slashes, and port numbers from URLs
|
|
11
|
-
* Matches:
|
|
12
|
-
* - http:// or https:// protocol
|
|
13
|
-
* - ws:// or wss:// protocol
|
|
14
|
-
* - trailing slashes
|
|
15
|
-
* - port numbers with colon
|
|
16
|
-
*
|
|
17
|
-
* @internal
|
|
18
|
-
*/
|
|
19
|
-
export const STRIP_REGEX =
|
|
20
|
-
/^(?:https?:\/\/)|^(?:wss?:\/\/)|(?:\/+$)|(?::\d+$)/g;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Checks if a domain matches a wildcard pattern
|
|
24
|
-
*
|
|
25
|
-
* @param hostname - The hostname to check
|
|
26
|
-
* @param wildcardPattern - The wildcard pattern (e.g. *.example.com)
|
|
27
|
-
* @param logger - Optional logger for debugging
|
|
28
|
-
* @returns true if the hostname matches the wildcard pattern
|
|
29
|
-
*
|
|
30
|
-
* @internal
|
|
31
|
-
*/
|
|
32
|
-
function matchesWildcard(
|
|
33
|
-
hostname: string,
|
|
34
|
-
wildcardPattern: string,
|
|
35
|
-
logger?: Logger
|
|
36
|
-
): boolean {
|
|
37
|
-
const wildcardDomain = wildcardPattern.slice(2); // Remove *. prefix
|
|
38
|
-
|
|
39
|
-
// Ensure the hostname is not the base domain and ends with .wildcardDomain
|
|
40
|
-
// This prevents matching domains like 'foobar-my-site.com' against '*.my-site.com'
|
|
41
|
-
const isValid =
|
|
42
|
-
hostname !== wildcardDomain && hostname.endsWith(`.${wildcardDomain}`);
|
|
43
|
-
|
|
44
|
-
logger?.debug(
|
|
45
|
-
`Wildcard match result: ${isValid} ${hostname} ends with .${wildcardDomain}`
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
return isValid;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Validates if a given origin matches any of the trusted domain patterns
|
|
53
|
-
*
|
|
54
|
-
* Supports:
|
|
55
|
-
* - Exact domain matches
|
|
56
|
-
* - Wildcard subdomains (e.g. *.example.com)
|
|
57
|
-
* - Protocol-agnostic matching
|
|
58
|
-
* - Case-insensitive comparison
|
|
59
|
-
*
|
|
60
|
-
* @param origin - The origin URL to validate (e.g. https://example.com)
|
|
61
|
-
* @param trustedDomains - Array of trusted domain patterns. Can include wildcards (e.g. *.example.com)
|
|
62
|
-
* @param logger - Optional logger for debugging validation process
|
|
63
|
-
*
|
|
64
|
-
* @returns `true` if the origin matches any trusted domain pattern, `false` otherwise
|
|
65
|
-
*
|
|
66
|
-
* @throws {Error} When trustedDomains array is empty
|
|
67
|
-
* @throws {TypeError} When origin URL is invalid
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```ts
|
|
71
|
-
* // Simple domain matching
|
|
72
|
-
* isOriginTrusted('https://example.com', ['example.com']); // true
|
|
73
|
-
*
|
|
74
|
-
* // Wildcard subdomain matching
|
|
75
|
-
* isOriginTrusted('https://api.example.com', ['*.example.com']); // true
|
|
76
|
-
*
|
|
77
|
-
* // Allow all origins
|
|
78
|
-
* isOriginTrusted('https://any-domain.com', ['*']); // true
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
|
-
export function isOriginTrusted(
|
|
82
|
-
origin: string,
|
|
83
|
-
trustedDomains: string[],
|
|
84
|
-
logger?: Logger
|
|
85
|
-
): boolean {
|
|
86
|
-
try {
|
|
87
|
-
if (trustedDomains.length === 0) {
|
|
88
|
-
throw new Error('No trusted domains');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
logger?.debug(
|
|
92
|
-
`Checking if origin ${origin} is trusted in ${trustedDomains}`
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
// Special case: if "*" is in trusted domains, allow all origins
|
|
96
|
-
if (trustedDomains.includes('*')) {
|
|
97
|
-
logger?.debug('Allowing all origins');
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Parse the origin URL to get just the hostname
|
|
102
|
-
const url = new URL(origin);
|
|
103
|
-
const originHostname = url.hostname.toLowerCase();
|
|
104
|
-
logger?.debug(`Parsed origin hostname: ${originHostname}`);
|
|
105
|
-
|
|
106
|
-
return trustedDomains.some((domain) => {
|
|
107
|
-
// Handle empty domains (which might come from splitting empty strings)
|
|
108
|
-
if (!domain || domain.trim() === '') {
|
|
109
|
-
logger?.debug('Skipping empty domain');
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const strippedDomain = domain.replace(STRIP_REGEX, '').toLowerCase();
|
|
114
|
-
logger?.debug(`Checking against stripped domain: ${strippedDomain}`);
|
|
115
|
-
|
|
116
|
-
if (strippedDomain.startsWith('*.')) {
|
|
117
|
-
return matchesWildcard(originHostname, strippedDomain, logger);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const isMatch = originHostname === strippedDomain;
|
|
121
|
-
logger?.debug(
|
|
122
|
-
`Exact match result: ${isMatch} ${originHostname} === ${strippedDomain}`
|
|
123
|
-
);
|
|
124
|
-
return isMatch;
|
|
125
|
-
});
|
|
126
|
-
} catch (error) {
|
|
127
|
-
logger?.error('Error validating origin:', error);
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CORS processing middleware for c15t
|
|
3
|
-
* Handles origin validation and context enrichment
|
|
4
|
-
*
|
|
5
|
-
* @packageDocumentation
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { C15TContext } from '~/types';
|
|
9
|
-
import { isOriginTrusted } from './is-origin-trusted';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Result of CORS processing
|
|
13
|
-
* @internal
|
|
14
|
-
*/
|
|
15
|
-
interface CORSProcessingResult {
|
|
16
|
-
/** The origin from the request */
|
|
17
|
-
origin: string | null;
|
|
18
|
-
/** Whether the origin is trusted */
|
|
19
|
-
isTrusted: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Extracts and validates CORS information from a request
|
|
24
|
-
*
|
|
25
|
-
* @param request - The request to process
|
|
26
|
-
* @param trustedOrigins - Array of trusted origins
|
|
27
|
-
* @param logger - Optional logger for debugging
|
|
28
|
-
* @returns CORS processing result
|
|
29
|
-
*
|
|
30
|
-
* @internal
|
|
31
|
-
*/
|
|
32
|
-
function extractCORSInfo(
|
|
33
|
-
request: Request,
|
|
34
|
-
trustedOrigins?: string[],
|
|
35
|
-
logger?: C15TContext['logger']
|
|
36
|
-
): CORSProcessingResult {
|
|
37
|
-
const origin = request.headers.get('origin');
|
|
38
|
-
|
|
39
|
-
if (!origin || !trustedOrigins) {
|
|
40
|
-
return {
|
|
41
|
-
origin: origin,
|
|
42
|
-
isTrusted: false,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
origin,
|
|
48
|
-
isTrusted: isOriginTrusted(origin, trustedOrigins, logger),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Processes CORS validation for an incoming request and enriches the context
|
|
54
|
-
* with origin information. This middleware function validates the origin against
|
|
55
|
-
* trusted patterns and updates the context with the validation results.
|
|
56
|
-
*
|
|
57
|
-
* @param request - The incoming HTTP request to process
|
|
58
|
-
* @param context - The c15t middleware context to enrich
|
|
59
|
-
* @param trustedOrigins - Array of trusted origin patterns. Can include wildcards ('*')
|
|
60
|
-
*
|
|
61
|
-
* @returns The enriched context with origin validation results
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* ```ts
|
|
65
|
-
* const enrichedContext = processCors(
|
|
66
|
-
* request,
|
|
67
|
-
* context,
|
|
68
|
-
* ['https://example.com', '*.trusted-domain.com']
|
|
69
|
-
* );
|
|
70
|
-
* ```
|
|
71
|
-
*
|
|
72
|
-
* @see {@link isOriginTrusted} for origin validation details
|
|
73
|
-
*/
|
|
74
|
-
export const processCors = (
|
|
75
|
-
request: Request,
|
|
76
|
-
context: C15TContext,
|
|
77
|
-
trustedOrigins?: string[]
|
|
78
|
-
): C15TContext => {
|
|
79
|
-
const { origin, isTrusted } = extractCORSInfo(
|
|
80
|
-
request,
|
|
81
|
-
trustedOrigins,
|
|
82
|
-
context.logger
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
if (origin) {
|
|
86
|
-
context.origin = origin;
|
|
87
|
-
context.trustedOrigin = isTrusted;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return context;
|
|
91
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { C15TOptions } from '~/types';
|
|
2
|
-
import { version } from '~/version';
|
|
3
|
-
/**
|
|
4
|
-
* Default OpenAPI configuration
|
|
5
|
-
*
|
|
6
|
-
* Note: specPath and docsPath should NOT include the basePath,
|
|
7
|
-
* as the basePath is stripped from incoming requests before routing.
|
|
8
|
-
*/
|
|
9
|
-
export const createOpenAPIConfig = (options: C15TOptions) => {
|
|
10
|
-
return {
|
|
11
|
-
enabled: options.advanced?.openapi?.enabled !== false,
|
|
12
|
-
specPath: '/spec.json',
|
|
13
|
-
docsPath: '/docs',
|
|
14
|
-
...(options.advanced?.openapi || {}),
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Default OpenAPI options
|
|
20
|
-
*/
|
|
21
|
-
export const createDefaultOpenAPIOptions = (options: C15TOptions) => ({
|
|
22
|
-
info: {
|
|
23
|
-
title: options.appName || 'c15t API',
|
|
24
|
-
version,
|
|
25
|
-
description: 'API for consent management',
|
|
26
|
-
},
|
|
27
|
-
servers: [{ url: options.basePath || '/' }],
|
|
28
|
-
security: [{ bearerAuth: [] }],
|
|
29
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { C15TOptions } from '~/types';
|
|
2
|
-
import { createOpenAPIConfig } from './config';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Generate the default UI for API documentation
|
|
6
|
-
*/
|
|
7
|
-
export const createDocsUI = (options: C15TOptions) => {
|
|
8
|
-
const config = createOpenAPIConfig(options);
|
|
9
|
-
|
|
10
|
-
// If a custom template is provided, use it
|
|
11
|
-
if (config.customUiTemplate) {
|
|
12
|
-
return config.customUiTemplate;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Otherwise, return the default Scalar UI
|
|
16
|
-
return `
|
|
17
|
-
<!doctype html>
|
|
18
|
-
<html>
|
|
19
|
-
<head>
|
|
20
|
-
<title>${options.appName || 'c15t API'} Documentation</title>
|
|
21
|
-
<meta charset="utf-8" />
|
|
22
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
23
|
-
<link rel="icon" type="image/svg+xml" href="https://c15t.com/icon.svg" />
|
|
24
|
-
</head>
|
|
25
|
-
<body>
|
|
26
|
-
<script
|
|
27
|
-
id="api-reference"
|
|
28
|
-
data-url="${encodeURI(config.specPath)}">
|
|
29
|
-
</script>
|
|
30
|
-
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
31
|
-
</body>
|
|
32
|
-
</html>
|
|
33
|
-
`;
|
|
34
|
-
};
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { C15TOptions } from '~/types';
|
|
3
|
-
import { getIpAddress, maskIpAddress } from './index';
|
|
4
|
-
|
|
5
|
-
describe('maskIpAddress', () => {
|
|
6
|
-
describe('IPv4 addresses', () => {
|
|
7
|
-
it('should mask the last octet of a standard IPv4 address', () => {
|
|
8
|
-
expect(maskIpAddress('192.168.1.100')).toBe('192.168.1.0');
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should mask the last octet of localhost', () => {
|
|
12
|
-
expect(maskIpAddress('127.0.0.1')).toBe('127.0.0.0');
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('should mask the last octet of a public IP', () => {
|
|
16
|
-
expect(maskIpAddress('8.8.8.8')).toBe('8.8.8.0');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should handle IP with last octet already zero', () => {
|
|
20
|
-
expect(maskIpAddress('10.0.0.0')).toBe('10.0.0.0');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should handle IP with max values', () => {
|
|
24
|
-
expect(maskIpAddress('255.255.255.255')).toBe('255.255.255.0');
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
describe('IPv6 addresses', () => {
|
|
29
|
-
it('should mask the last 80 bits of a full IPv6 address', () => {
|
|
30
|
-
const result = maskIpAddress('2001:0db8:85a3:0000:0000:8a2e:0370:7334');
|
|
31
|
-
expect(result).toBe('2001:db8:85a3::');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should mask a compressed IPv6 address', () => {
|
|
35
|
-
const result = maskIpAddress('2001:db8:85a3::1');
|
|
36
|
-
expect(result).toBe('2001:db8:85a3::');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should handle localhost IPv6', () => {
|
|
40
|
-
const result = maskIpAddress('::1');
|
|
41
|
-
expect(result).toBe('::');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should handle full zeros IPv6', () => {
|
|
45
|
-
const result = maskIpAddress('::');
|
|
46
|
-
expect(result).toBe('::');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should mask IPv6 with leading zeros compressed', () => {
|
|
50
|
-
const result = maskIpAddress('::ffff:0:0:1');
|
|
51
|
-
expect(result).toBe('::');
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
describe('IPv4-mapped IPv6 addresses', () => {
|
|
56
|
-
it('should mask the IPv4 portion of IPv4-mapped IPv6', () => {
|
|
57
|
-
const result = maskIpAddress('::ffff:192.168.1.100');
|
|
58
|
-
expect(result).toBe('::ffff:192.168.1.0');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should handle IPv4-mapped IPv6 localhost', () => {
|
|
62
|
-
const result = maskIpAddress('::ffff:127.0.0.1');
|
|
63
|
-
expect(result).toBe('::ffff:127.0.0.0');
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
describe('edge cases', () => {
|
|
68
|
-
it('should return null for null input', () => {
|
|
69
|
-
expect(maskIpAddress(null)).toBeNull();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should return null for empty string', () => {
|
|
73
|
-
expect(maskIpAddress('')).toBeNull();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should handle malformed IPv4 gracefully', () => {
|
|
77
|
-
expect(maskIpAddress('192.168.1')).toBe('192.168.1');
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
describe('getIpAddress', () => {
|
|
83
|
-
const createMockHeaders = (headers: Record<string, string>): Headers => {
|
|
84
|
-
return new Headers(headers);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const createBaseOptions = (
|
|
88
|
-
ipAddressOverrides?: NonNullable<C15TOptions['advanced']>['ipAddress']
|
|
89
|
-
): C15TOptions => ({
|
|
90
|
-
trustedOrigins: ['http://localhost'],
|
|
91
|
-
adapter: {} as C15TOptions['adapter'],
|
|
92
|
-
advanced: {
|
|
93
|
-
ipAddress: ipAddressOverrides,
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe('IP extraction', () => {
|
|
98
|
-
it('should extract and mask IP from x-forwarded-for header by default', () => {
|
|
99
|
-
const headers = createMockHeaders({
|
|
100
|
-
'x-forwarded-for': '192.168.1.100, 10.0.0.1',
|
|
101
|
-
});
|
|
102
|
-
const options = createBaseOptions();
|
|
103
|
-
|
|
104
|
-
expect(getIpAddress(headers, options)).toBe('192.168.1.0');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should extract and mask IP from cf-connecting-ip header by default', () => {
|
|
108
|
-
const headers = createMockHeaders({
|
|
109
|
-
'cf-connecting-ip': '8.8.8.8',
|
|
110
|
-
});
|
|
111
|
-
const options = createBaseOptions();
|
|
112
|
-
|
|
113
|
-
expect(getIpAddress(headers, options)).toBe('8.8.8.0');
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should return null when no IP headers present', () => {
|
|
117
|
-
const headers = createMockHeaders({});
|
|
118
|
-
const options = createBaseOptions();
|
|
119
|
-
|
|
120
|
-
expect(getIpAddress(headers, options)).toBeNull();
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('IP tracking disabled', () => {
|
|
125
|
-
it('should return null when IP tracking is disabled', () => {
|
|
126
|
-
const headers = createMockHeaders({
|
|
127
|
-
'x-forwarded-for': '192.168.1.100',
|
|
128
|
-
});
|
|
129
|
-
const options = createBaseOptions({
|
|
130
|
-
tracking: false,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
expect(getIpAddress(headers, options)).toBeNull();
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe('IP masking enabled', () => {
|
|
138
|
-
it('should mask IPv4 address when masking is enabled', () => {
|
|
139
|
-
const headers = createMockHeaders({
|
|
140
|
-
'x-forwarded-for': '192.168.1.100',
|
|
141
|
-
});
|
|
142
|
-
const options = createBaseOptions({
|
|
143
|
-
masking: true,
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
expect(getIpAddress(headers, options)).toBe('192.168.1.0');
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should mask IPv6 address when masking is enabled', () => {
|
|
150
|
-
const headers = createMockHeaders({
|
|
151
|
-
'x-forwarded-for': '2001:db8:85a3::8a2e:370:7334',
|
|
152
|
-
});
|
|
153
|
-
const options = createBaseOptions({
|
|
154
|
-
masking: true,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
expect(getIpAddress(headers, options)).toBe('2001:db8:85a3::');
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('should mask by default when masking is not explicitly disabled', () => {
|
|
161
|
-
const headers = createMockHeaders({
|
|
162
|
-
'x-forwarded-for': '192.168.1.100',
|
|
163
|
-
});
|
|
164
|
-
const options = createBaseOptions();
|
|
165
|
-
|
|
166
|
-
expect(getIpAddress(headers, options)).toBe('192.168.1.0');
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('should not mask when masking is explicitly false', () => {
|
|
170
|
-
const headers = createMockHeaders({
|
|
171
|
-
'x-forwarded-for': '192.168.1.100',
|
|
172
|
-
});
|
|
173
|
-
const options = createBaseOptions({
|
|
174
|
-
masking: false,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
expect(getIpAddress(headers, options)).toBe('192.168.1.100');
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe('custom headers', () => {
|
|
182
|
-
it('should use custom IP headers when provided', () => {
|
|
183
|
-
const headers = createMockHeaders({
|
|
184
|
-
'x-custom-ip': '10.0.0.1',
|
|
185
|
-
'x-forwarded-for': '192.168.1.100',
|
|
186
|
-
});
|
|
187
|
-
const options = createBaseOptions({
|
|
188
|
-
ipAddressHeaders: ['x-custom-ip'],
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
// Masking is on by default, so last octet is zeroed
|
|
192
|
-
expect(getIpAddress(headers, options)).toBe('10.0.0.0');
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
});
|