@adobe/spacecat-shared-data-access 3.68.0 → 3.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [@adobe/spacecat-shared-data-access-v3.70.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.69.0...@adobe/spacecat-shared-data-access-v3.70.0) (2026-05-22)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **data-access:** extend DOMAIN_PATTERN to support subpath domains (LLMO-4187) ([#1593](https://github.com/adobe/spacecat-shared/issues/1593)) ([f6cd505](https://github.com/adobe/spacecat-shared/commit/f6cd505da6c61936538a39b26465c2bdc1c3863b))
|
|
6
|
+
|
|
7
|
+
## [@adobe/spacecat-shared-data-access-v3.69.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.68.0...@adobe/spacecat-shared-data-access-v3.69.0) (2026-05-22)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* expose config.defaults via getDefaults() and include in toDynamoItem ([#1613](https://github.com/adobe/spacecat-shared/issues/1613)) ([782503d](https://github.com/adobe/spacecat-shared/commit/782503d8880054bcf0c65fdce987520e28950133))
|
|
12
|
+
|
|
1
13
|
## [@adobe/spacecat-shared-data-access-v3.68.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.67.0...@adobe/spacecat-shared-data-access-v3.68.0) (2026-05-21)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/package.json
CHANGED
|
@@ -24,7 +24,90 @@ class PlgOnboarding extends BaseModel {
|
|
|
24
24
|
|
|
25
25
|
static IMS_ORG_ID_PATTERN = /^[a-z0-9]{24}@AdobeOrg$/i;
|
|
26
26
|
|
|
27
|
-
static
|
|
27
|
+
static MAX_HOSTNAME_LENGTH = 253; // RFC 1035 DNS name limit
|
|
28
|
+
|
|
29
|
+
// Practical cap, chosen for storage and sort-key index depth rather than for any
|
|
30
|
+
// specific browser/URL-bar limit (the domain field is a stored identifier, not a URL).
|
|
31
|
+
static MAX_DOMAIN_LENGTH = 2048;
|
|
32
|
+
|
|
33
|
+
// **WARNING for external consumers: do NOT use DOMAIN_PATTERN directly.**
|
|
34
|
+
// This regex is incomplete on its own — it has no length cap, no control-character
|
|
35
|
+
// rejection, no all-numeric-hostname check, no trailing-dot/consecutive-dot path
|
|
36
|
+
// rejection, and no typeof guard. Always call `PlgOnboarding.isValidDomain(value)`
|
|
37
|
+
// which composes this regex with the rest of the validator. The regex is exported
|
|
38
|
+
// only for legacy callers and may become module-private in a future major release.
|
|
39
|
+
//
|
|
40
|
+
// Matches lowercase hostnames (at least one dot required) and an optional subpath
|
|
41
|
+
// (e.g. nba.com, nba.com/kings, nba.com/us/kings).
|
|
42
|
+
// The final label (TLD) must be alphabetic (>= 2 chars) or punycode (xn--*). This
|
|
43
|
+
// structurally rejects every IP-literal form: dotted-quad (127.0.0.1), short-form
|
|
44
|
+
// (127.1), decimal (2130706433), hex (0x7f.0.0.1, 0xa9.254.169.254 → AWS IMDS),
|
|
45
|
+
// and octal (0177.0.0.1) — and also blocks foo.1-style typos. WHATWG URL would
|
|
46
|
+
// otherwise canonicalize hex/decimal IPs to their dotted-quad form, bypassing
|
|
47
|
+
// denylist-based SSRF gates downstream.
|
|
48
|
+
// Rejects: uppercase letters (use normalizeDomain() first), schemes (https://),
|
|
49
|
+
// ports (:8080), single-label hostnames (localhost, metadata), query strings,
|
|
50
|
+
// fragments, empty/trailing path segments, and any path segment starting with
|
|
51
|
+
// a dot (blocks ./, ../, .hidden, ..foo, etc.).
|
|
52
|
+
// Path-qualified domains (nba.com/kings) are distinct sort-key values from the bare
|
|
53
|
+
// hostname; callers must call normalizeDomain() before findByImsOrgIdAndDomain.
|
|
54
|
+
// Labels must not start or end with a hyphen (RFC 1035).
|
|
55
|
+
// Raw Unicode / IDN must be punycode-encoded before validation (xn-- form is accepted).
|
|
56
|
+
// Percent-encoded path characters (%20 etc.) are not accepted; decode before validation.
|
|
57
|
+
// Underscore is allowed in path segments but not in hostname labels.
|
|
58
|
+
static DOMAIN_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*\.(?:[a-z]{2,}|xn--[a-z0-9-]+)(\/(?!\.)[a-z0-9._~-]+)*$/;
|
|
59
|
+
|
|
60
|
+
// Returns the canonical form of a domain value: lowercased.
|
|
61
|
+
// Note: non-string inputs (null/undefined/number/object) are returned unchanged.
|
|
62
|
+
// Callers MUST also run `isValidDomain(value)` before using the result — calling
|
|
63
|
+
// `normalizeDomain` alone does not guarantee the value is a string or safe to
|
|
64
|
+
// pass to `findByImsOrgIdAndDomain` (which would otherwise treat a non-string
|
|
65
|
+
// sort key as something it isn't).
|
|
66
|
+
static normalizeDomain(value) {
|
|
67
|
+
return typeof value === 'string' ? value.toLowerCase() : value;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Complete domain validator used by the schema and intended for external consumers.
|
|
71
|
+
// Layers a typeof guard, case-canonical check, control-character rejection,
|
|
72
|
+
// all-numeric-hostname rejection (defense-in-depth; DOMAIN_PATTERN's alphabetic-TLD
|
|
73
|
+
// requirement already rejects dotted-quad, short-form, decimal, hex, and octal IPs),
|
|
74
|
+
// trailing-dot path-segment rejection, DOMAIN_PATTERN test, and length caps.
|
|
75
|
+
// Note: DOMAIN_PATTERN alone is not sufficient — always prefer this method.
|
|
76
|
+
// Lowercase-only (host AND path) is intentional canonicalization, not a bug. The
|
|
77
|
+
// domain field is part of the dedup sort key on findByImsOrgIdAndDomain; allowing
|
|
78
|
+
// mixed-case paths would let `nba.com/Kings` and `nba.com/kings` create distinct
|
|
79
|
+
// onboarding rows for the same site. Callers should call normalizeDomain() first.
|
|
80
|
+
// This is a syntactic / data-integrity validator, not an SSRF gate. Callers that
|
|
81
|
+
// make outbound fetches must layer their own private-IP and DNS-resolution checks.
|
|
82
|
+
static isValidDomain(value) {
|
|
83
|
+
if (typeof value !== 'string' || value !== value.toLowerCase()) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
// Length caps run BEFORE the regex test so a multi-MB pathological input is
|
|
87
|
+
// rejected in O(1) rather than driving a multi-MB regex scan. The regex itself
|
|
88
|
+
// is linear (no overlapping quantifiers) but external consumers may not bound
|
|
89
|
+
// input size upstream.
|
|
90
|
+
if (value.length > PlgOnboarding.MAX_DOMAIN_LENGTH) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (/[^\x21-\x7e]/.test(value)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
const [hostname, ...pathParts] = value.split('/');
|
|
97
|
+
if (hostname.length > PlgOnboarding.MAX_HOSTNAME_LENGTH) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
if (/^[\d.]+$/.test(hostname)) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
// Reject path segments that are purely dots, end with a dot, or contain
|
|
104
|
+
// consecutive dots (foo., foo.., foo../bar, v1..0). DOMAIN_PATTERN's
|
|
105
|
+
// negative lookahead only blocks segments STARTING with a dot.
|
|
106
|
+
if (pathParts.some((seg) => /\.$/.test(seg) || seg.includes('..'))) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
return PlgOnboarding.DOMAIN_PATTERN.test(value);
|
|
110
|
+
}
|
|
28
111
|
|
|
29
112
|
static STATUSES = {
|
|
30
113
|
PRE_ONBOARDING: 'PRE_ONBOARDING',
|
|
@@ -28,7 +28,7 @@ const schema = new SchemaBuilder(PlgOnboarding, PlgOnboardingCollection)
|
|
|
28
28
|
type: 'string',
|
|
29
29
|
required: true,
|
|
30
30
|
readOnly: true,
|
|
31
|
-
validate: (value) => PlgOnboarding.
|
|
31
|
+
validate: (value) => PlgOnboarding.isValidDomain(value),
|
|
32
32
|
})
|
|
33
33
|
.addAttribute('baseURL', {
|
|
34
34
|
type: 'string',
|
|
@@ -524,6 +524,7 @@ export const Config = (data = {}) => {
|
|
|
524
524
|
self.getIncludedURLs = (type) => state?.handlers?.[type]?.includedURLs;
|
|
525
525
|
self.getGroupedURLs = (type) => state?.handlers?.[type]?.groupedURLs;
|
|
526
526
|
self.getLatestMetrics = (type) => state?.handlers?.[type]?.latestMetrics;
|
|
527
|
+
self.getDefaults = () => state?.defaults;
|
|
527
528
|
self.getFetchConfig = () => state?.fetchConfig;
|
|
528
529
|
self.getBrandConfig = () => state?.brandConfig;
|
|
529
530
|
self.getBrandProfile = () => state?.brandProfile;
|
|
@@ -995,6 +996,7 @@ Config.fromDynamoItem = (dynamoItem) => Config(dynamoItem);
|
|
|
995
996
|
Config.toDynamoItem = (config) => ({
|
|
996
997
|
slack: config.getSlackConfig(),
|
|
997
998
|
handlers: config.getHandlers(),
|
|
999
|
+
defaults: config.getDefaults?.(),
|
|
998
1000
|
contentAiConfig: config.getContentAiConfig(),
|
|
999
1001
|
imports: config.getImports(),
|
|
1000
1002
|
fetchConfig: config.getFetchConfig(),
|