cabloy 5.1.187 → 5.1.189
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/.cabloy-version +1 -1
- package/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/repo-docs/backend/runtime-and-flavors.md +1 -1
- package/repo-e2e/specs/markdown.spec.ts +46 -1
- package/vona/docker-compose-original/config/nginx/conf.d/nginx.conf +2 -2
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +1 -1
- package/vona/packages-vona/vona-core/src/lib/core/application.ts +12 -5
- package/vona/packages-vona/vona-core/src/lib/core/context.ts +1 -1
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/pnpm-lock.yaml +14 -136
- package/vona/src/suite/a-home/modules/home-user/src/service/account.ts +1 -1
- package/vona/src/suite/a-home/modules/home-user/test/accountPasswordReset.test.ts +24 -5
- package/vona/src/suite/a-home/modules/home-user/test/accountPasswordSet.test.ts +22 -5
- package/vona/src/suite-vendor/a-auth/modules/a-auth/package.json +1 -1
- package/vona/src/suite-vendor/a-auth/modules/a-auth/src/lib/utils.ts +42 -0
- package/vona/src/suite-vendor/a-auth/modules/a-auth/src/service/auth.ts +60 -2
- package/vona/src/suite-vendor/a-auth/modules/a-auth/test/authCallbackRedirect.test.ts +44 -0
- package/vona/src/suite-vendor/a-auth/modules/a-auth/test/oauthRequestContext.test.ts +171 -0
- package/vona/src/suite-vendor/a-auth/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-socket/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-socket/src/bean/socketConnection.cors.ts +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-security/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-security/src/bean/middlewareSystem.cors.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-version/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-version/src/lib/databaseTestName.ts +47 -0
- package/vona/src/suite-vendor/a-vona/modules/a-version/src/service/database.ts +8 -3
- package/vona/src/suite-vendor/a-vona/modules/a-version/test/databaseName.test.ts +72 -0
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/package.json +2 -2
- package/zova/packages-utils/zova-vite/package.json +1 -1
- package/zova/packages-utils/zova-vite/src/collect-css-ssr.ts +7 -5
- package/zova/pnpm-lock.yaml +16 -16
- package/zova/src/suite/a-home/modules/home-base/src/config/config.ts +0 -8
- package/zova/src/suite/a-home/modules/home-base/src/service/ssrLayout.ts +2 -3
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +1 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.sidebar.tsx +1 -4
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/config/config.ts +4 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +1 -0
- package/zova/src/suite/cabloy-basic/modules/basic-markdown/src/lib/richTextContentStyle.ts +16 -2
package/.cabloy-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.1.
|
|
1
|
+
5.1.189
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.189
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add anonymous context creation support.
|
|
8
|
+
- Add home user functionality.
|
|
9
|
+
- Add application host utility access through the context.
|
|
10
|
+
- Add authentication enhancements.
|
|
11
|
+
- Update core feature behavior.
|
|
12
|
+
|
|
13
|
+
## 5.1.188
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- Enforce database name length limits.
|
|
18
|
+
- Correct markdown task list item rendering.
|
|
19
|
+
|
|
20
|
+
### Improvements
|
|
21
|
+
|
|
22
|
+
- Refactor the layout implementation.
|
|
23
|
+
- Update SSR CSS collection handling.
|
|
24
|
+
|
|
3
25
|
## 5.1.187
|
|
4
26
|
|
|
5
27
|
### Improvements
|
package/package.json
CHANGED
|
@@ -133,7 +133,7 @@ Use this page as the runtime-facing overview, then inspect the current app confi
|
|
|
133
133
|
|
|
134
134
|
When configured, `SERVER_SERVE_PROTOCOL` and `SERVER_SERVE_HOST` define Vona's canonical public origin for backend APIs and backend-hosted SSR sites. If either serve value is not configured, Vona resolves the effective protocol and host from the current proxy-aware request context; background work that needs a stable backend public origin should configure both serve values explicitly.
|
|
135
135
|
|
|
136
|
-
A browser consumer can be deployed on a different origin and pathname. Account password-set and password-reset delivery
|
|
136
|
+
A browser consumer can be deployed on a different origin and pathname. Account password-set and password-reset delivery does not derive its destination from SSR Site metadata, `publicPath`, `siteId`, `Referer`, or browser-selected mount data: Zova supplies the complete token-free absolute public page URL, and Vona validates only HTTP(S), absence of userinfo/query/fragment, and an exact trusted origin. Production origin checks supply `app.util.host` as their same-host authority: when configured, `SERVER_SERVE_HOST` is the canonical host; otherwise Vona falls back to the current proxy-aware request host. `checkOriginExact` permits an origin whose protocol, canonical/fallback host, and effective port match; request or proxy Host values are not a general cross-origin allowlist and cannot authorize lookalike, suffix, alternate-scheme, or alternate-port destinations when a canonical host is configured. Other production consumer origins must exactly match an explicit `a-security:cors` `whiteList` entry. This change supplies the canonical host only; `checkOriginExact` continues to obtain the protocol from the active request context. In `dev/test`, exact credential-link authorization additionally accepts different ports only when both API and consumer hostnames are loopback (`localhost`, `127.0.0.1`, or `::1`). Vona preserves the frontend pathname and alone adds the raw token as the `token` URL query parameter. Query transport reaches the initial request; Referrer-Policy and Vona, edge, or APM query-log redaction are intentionally outside this flow's current scope. Normal CORS defaults to an empty `whiteList`; configure `CORS_WHITE_LIST` with the permitted browser origins, or explicitly configure `a-security:cors`. In `dev/test`, loopback requests may cross ports; elsewhere, cross-origin CORS requires an allowed entry. Normal CORS wildcard and suffix matching remain available when configured but are not credential-link authorization.
|
|
137
137
|
|
|
138
138
|
## Configure browser CORS origins
|
|
139
139
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Page } from '@playwright/test';
|
|
1
|
+
import type { Locator, Page } from '@playwright/test';
|
|
2
2
|
|
|
3
3
|
import { expect, test } from '@playwright/test';
|
|
4
4
|
|
|
@@ -35,6 +35,49 @@ function expectTableIdentity(value: unknown) {
|
|
|
35
35
|
expect(['string', 'number']).toContain(typeof value);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
async function expectTaskCheckboxLayout(root: Locator) {
|
|
39
|
+
const layout = await root.locator('ul[data-type="taskList"] li').evaluateAll(taskItems =>
|
|
40
|
+
taskItems.map(taskItem => {
|
|
41
|
+
const checkbox = taskItem.querySelector<HTMLInputElement>('label > input[type="checkbox"]');
|
|
42
|
+
const label = taskItem.querySelector<HTMLElement>('label');
|
|
43
|
+
const text = taskItem.querySelector<HTMLElement>('div > p');
|
|
44
|
+
if (!checkbox || !label || !text) return null;
|
|
45
|
+
|
|
46
|
+
const checkboxRect = checkbox.getBoundingClientRect();
|
|
47
|
+
const textRect = text.getBoundingClientRect();
|
|
48
|
+
const checkboxStyle = getComputedStyle(checkbox);
|
|
49
|
+
const labelStyle = getComputedStyle(label);
|
|
50
|
+
const itemStyle = getComputedStyle(taskItem);
|
|
51
|
+
return {
|
|
52
|
+
checkboxHeight: checkboxRect.height,
|
|
53
|
+
checkboxWidth: checkboxRect.width,
|
|
54
|
+
checkboxCenter: checkboxRect.top + checkboxRect.height / 2,
|
|
55
|
+
checkboxMarginBlockEnd: checkboxStyle.marginBlockEnd,
|
|
56
|
+
checkboxMarginBlockStart: checkboxStyle.marginBlockStart,
|
|
57
|
+
checkboxMarginInlineEnd: checkboxStyle.marginInlineEnd,
|
|
58
|
+
checkboxMarginInlineStart: checkboxStyle.marginInlineStart,
|
|
59
|
+
itemDisplay: itemStyle.display,
|
|
60
|
+
labelDisplay: labelStyle.display,
|
|
61
|
+
textCenter: textRect.top + Number.parseFloat(getComputedStyle(text).lineHeight) / 2,
|
|
62
|
+
};
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
expect(layout).toHaveLength(2);
|
|
67
|
+
for (const task of layout) {
|
|
68
|
+
expect(task).not.toBeNull();
|
|
69
|
+
expect(task?.itemDisplay).toBe('flex');
|
|
70
|
+
expect(task?.labelDisplay).toBe('flex');
|
|
71
|
+
expect(task?.checkboxWidth).toBeGreaterThan(0);
|
|
72
|
+
expect(task?.checkboxHeight).toBe(task?.checkboxWidth);
|
|
73
|
+
expect(task?.checkboxMarginBlockStart).toBe('0px');
|
|
74
|
+
expect(task?.checkboxMarginBlockEnd).toBe('0px');
|
|
75
|
+
expect(task?.checkboxMarginInlineStart).toBe('0px');
|
|
76
|
+
expect(task?.checkboxMarginInlineEnd).toBe('0px');
|
|
77
|
+
expect(Math.abs((task?.checkboxCenter ?? 0) - (task?.textCenter ?? 0))).toBeLessThanOrEqual(2);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
38
81
|
async function login(
|
|
39
82
|
page: Page,
|
|
40
83
|
path: string,
|
|
@@ -181,6 +224,7 @@ test(
|
|
|
181
224
|
await expect(description.locator('input[type="checkbox"]').nth(0)).toBeDisabled();
|
|
182
225
|
await expect(description.locator('input[type="checkbox"]').nth(1)).toBeChecked();
|
|
183
226
|
await expect(description.locator('input[type="checkbox"]').nth(1)).toBeDisabled();
|
|
227
|
+
await expectTaskCheckboxLayout(description);
|
|
184
228
|
expect(webPageErrors).toEqual([]);
|
|
185
229
|
expect(webConsoleErrors).toEqual([]);
|
|
186
230
|
} finally {
|
|
@@ -353,6 +397,7 @@ const product = '${suffix}';
|
|
|
353
397
|
await expect(editor.locator('input[type="checkbox"]')).toHaveCount(2);
|
|
354
398
|
await expect(editor.locator('input[type="checkbox"]').nth(0)).not.toBeChecked();
|
|
355
399
|
await expect(editor.locator('input[type="checkbox"]').nth(1)).toBeChecked();
|
|
400
|
+
await expectTaskCheckboxLayout(editor);
|
|
356
401
|
await expect(editor.locator('blockquote')).toHaveCSS('border-left-width', '4px');
|
|
357
402
|
await expect(editor.locator('pre')).toHaveCSS('overflow-x', 'auto');
|
|
358
403
|
await expect(editor.locator('table th').first()).toHaveCSS('font-weight', '600');
|
|
@@ -12,9 +12,9 @@ server {
|
|
|
12
12
|
proxy_http_version 1.1;
|
|
13
13
|
proxy_set_header X-Real-IP $remote_addr;
|
|
14
14
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
15
|
-
proxy_set_header X-Forwarded-Host $
|
|
15
|
+
proxy_set_header X-Forwarded-Host $host;
|
|
16
16
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
17
|
-
proxy_set_header Host $
|
|
17
|
+
proxy_set_header Host $host;
|
|
18
18
|
proxy_set_header X-NginX-Proxy true;
|
|
19
19
|
proxy_set_header Upgrade $http_upgrade;
|
|
20
20
|
proxy_set_header Connection "upgrade";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.100",
|
|
4
4
|
"gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
|
|
5
5
|
"description": "Vona is an intuitive, elegant and powerful Node.js framework for rapidly developing enterprise applications of any size",
|
|
6
6
|
"keywords": [
|
|
@@ -72,22 +72,29 @@ export class VonaApplication extends KoaApplication {
|
|
|
72
72
|
if (req) {
|
|
73
73
|
request = req;
|
|
74
74
|
} else {
|
|
75
|
-
const
|
|
75
|
+
const port = this.config?.server.listen.port ?? this.meta.env.SERVER_LISTEN_PORT;
|
|
76
|
+
const hostFallback = port ? `localhost:${port}` : 'localhost';
|
|
77
|
+
const protocol = (this.config ? this.util.protocol : undefined) || 'http';
|
|
78
|
+
const host = (this.config ? this.util.host : undefined) || hostFallback;
|
|
79
|
+
const hostname = new URL(`${protocol}://${host}`).hostname;
|
|
76
80
|
request = {
|
|
77
81
|
headers: {
|
|
78
82
|
'host': host,
|
|
79
|
-
'x-forwarded-for':
|
|
83
|
+
'x-forwarded-for': '127.0.0.1',
|
|
84
|
+
'x-forwarded-host': host,
|
|
85
|
+
'x-forwarded-proto': protocol,
|
|
80
86
|
},
|
|
81
87
|
query: {},
|
|
82
88
|
querystring: '',
|
|
83
89
|
host,
|
|
84
|
-
hostname
|
|
85
|
-
protocol
|
|
86
|
-
secure: '
|
|
90
|
+
hostname,
|
|
91
|
+
protocol,
|
|
92
|
+
secure: protocol === 'https',
|
|
87
93
|
method: 'POST',
|
|
88
94
|
url: '',
|
|
89
95
|
path: '',
|
|
90
96
|
socket: {
|
|
97
|
+
encrypted: protocol === 'https',
|
|
91
98
|
remoteAddress: '127.0.0.1',
|
|
92
99
|
remotePort: 7001,
|
|
93
100
|
},
|
|
@@ -127,7 +127,7 @@ export const contextBase: ContextBase = {
|
|
|
127
127
|
typeof statusOrOptions === 'number' ? { status: statusOrOptions } : (statusOrOptions ?? {});
|
|
128
128
|
// checkOrigin
|
|
129
129
|
if (!url.startsWith('/') && !options.trustedExternal) {
|
|
130
|
-
const origin = cast(self.app.bean).security.checkOrigin(url, self.host);
|
|
130
|
+
const origin = cast(self.app.bean).security.checkOrigin(url, self.app.util.host);
|
|
131
131
|
if (!origin) self.app.throw(403);
|
|
132
132
|
}
|
|
133
133
|
// throw
|
package/vona/pnpm-lock.yaml
CHANGED
|
@@ -741,11 +741,11 @@ importers:
|
|
|
741
741
|
specifier: npm:@cabloy/zod@4.3.8
|
|
742
742
|
version: '@cabloy/zod@4.3.8'
|
|
743
743
|
zova:
|
|
744
|
-
specifier: ^5.1.
|
|
745
|
-
version: 5.1.
|
|
744
|
+
specifier: ^5.1.166
|
|
745
|
+
version: 5.1.166(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3))
|
|
746
746
|
zova-jsx:
|
|
747
|
-
specifier: ^1.1.
|
|
748
|
-
version: 1.1.
|
|
747
|
+
specifier: ^1.1.92
|
|
748
|
+
version: 1.1.92(typescript@5.9.3)
|
|
749
749
|
zova-module-a-api:
|
|
750
750
|
specifier: ^5.1.22
|
|
751
751
|
version: 5.1.22
|
|
@@ -777,11 +777,11 @@ importers:
|
|
|
777
777
|
specifier: ^5.1.54
|
|
778
778
|
version: 5.1.54
|
|
779
779
|
zova-module-a-pay:
|
|
780
|
-
specifier: ^5.0.
|
|
780
|
+
specifier: ^5.0.9
|
|
781
781
|
version: 5.0.9
|
|
782
782
|
zova-module-a-router:
|
|
783
|
-
specifier: ^5.1.
|
|
784
|
-
version: 5.1.
|
|
783
|
+
specifier: ^5.1.41
|
|
784
|
+
version: 5.1.41
|
|
785
785
|
zova-module-a-routertabs:
|
|
786
786
|
specifier: ^5.1.34
|
|
787
787
|
version: 5.1.34
|
|
@@ -825,11 +825,11 @@ importers:
|
|
|
825
825
|
specifier: npm:@cabloy/zod@4.3.8
|
|
826
826
|
version: '@cabloy/zod@4.3.8'
|
|
827
827
|
zova:
|
|
828
|
-
specifier: ^5.1.
|
|
829
|
-
version: 5.1.
|
|
828
|
+
specifier: ^5.1.166
|
|
829
|
+
version: 5.1.166(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3))
|
|
830
830
|
zova-jsx:
|
|
831
|
-
specifier: ^1.1.
|
|
832
|
-
version: 1.1.
|
|
831
|
+
specifier: ^1.1.92
|
|
832
|
+
version: 1.1.92(typescript@5.9.3)
|
|
833
833
|
zova-module-a-api:
|
|
834
834
|
specifier: ^5.1.22
|
|
835
835
|
version: 5.1.22
|
|
@@ -861,11 +861,11 @@ importers:
|
|
|
861
861
|
specifier: ^5.1.54
|
|
862
862
|
version: 5.1.54
|
|
863
863
|
zova-module-a-pay:
|
|
864
|
-
specifier: ^5.0.
|
|
864
|
+
specifier: ^5.0.9
|
|
865
865
|
version: 5.0.9
|
|
866
866
|
zova-module-a-router:
|
|
867
|
-
specifier: ^5.1.
|
|
868
|
-
version: 5.1.
|
|
867
|
+
specifier: ^5.1.41
|
|
868
|
+
version: 5.1.41
|
|
869
869
|
zova-module-a-routertabs:
|
|
870
870
|
specifier: ^5.1.34
|
|
871
871
|
version: 5.1.34
|
|
@@ -8890,15 +8890,9 @@ packages:
|
|
|
8890
8890
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
|
8891
8891
|
engines: {node: '>=10'}
|
|
8892
8892
|
|
|
8893
|
-
zova-core@5.1.91:
|
|
8894
|
-
resolution: {integrity: sha512-5e4EgInhcU7LUMhl6x7oOQnsF2X3lk1HMRvbo882FZrwTB3lvIz/ejOOdpRxoId29hqxvX5HFiKcb9aZi/cHog==}
|
|
8895
|
-
|
|
8896
8893
|
zova-core@5.1.92:
|
|
8897
8894
|
resolution: {integrity: sha512-Y6j3YCMlVCZ5f9JGRX79mFRYW96stGgnhTyMmo0LZCD/P3CqjIlNwyL8edK8e/DBzQ+JYFj65CuBf/n/lIcl7Q==}
|
|
8898
8895
|
|
|
8899
|
-
zova-jsx@1.1.91:
|
|
8900
|
-
resolution: {integrity: sha512-VIScqEFG6jwzNqjW7MvBvZdLJAqpkzchop6Q/g2ttGBKXMGjyTZnaISrB3gWv/feReGnUb0BFPzDgmrOdFnQgA==}
|
|
8901
|
-
|
|
8902
8896
|
zova-jsx@1.1.92:
|
|
8903
8897
|
resolution: {integrity: sha512-cbjpwK8qI3ufIKNXlYuWsbljfIbxZ3ISQXKKXn199V7A4IDRz0CNUmffPHU0EX3uZ1mMvqkt9HUJxaVseFb0qQ==}
|
|
8904
8898
|
|
|
@@ -8950,9 +8944,6 @@ packages:
|
|
|
8950
8944
|
zova-module-a-pay@5.0.9:
|
|
8951
8945
|
resolution: {integrity: sha512-Chl6EKp30HBOGFCJXbla2/lS19WhzQyTZwgYmsL3nnG9Vt2TeUlb82vsYCVuDcy0cgmxVaWjPF7dzKL/r3Pfng==}
|
|
8952
8946
|
|
|
8953
|
-
zova-module-a-router@5.1.40:
|
|
8954
|
-
resolution: {integrity: sha512-X8sOcMqDrNju+J+kjpyRwUkecMdnXIq2MFbl3KLY1lb641sXLEmdJMSJBmVWCrGVBA+kA6nGnI//wtMGXTVIyg==}
|
|
8955
|
-
|
|
8956
8947
|
zova-module-a-router@5.1.41:
|
|
8957
8948
|
resolution: {integrity: sha512-oSv4S+9bAx79X8oUBARFKs4n56FNG/bbqdyxP10CXxlVue8WU7CmNKN4ckzLJ2mleVIezijZk/1aHS1Fl5rk+g==}
|
|
8958
8949
|
|
|
@@ -8980,9 +8971,6 @@ packages:
|
|
|
8980
8971
|
zova-module-a-zod@5.1.37:
|
|
8981
8972
|
resolution: {integrity: sha512-rXHN9rKbum9w3gDSnC/pIusG2d2FGJOcIauf8jrbT96f+Olk4Q3iV3t2V92mxiLCh9kMvBJPfcOgJFW7pRB5Fw==}
|
|
8982
8973
|
|
|
8983
|
-
zova-module-a-zova@5.1.107:
|
|
8984
|
-
resolution: {integrity: sha512-apqfQ2DSDd/2witE+qeVXOC5pxG4cqt0hfiXfJVHcfLeius4h9lpnLFQqFswkyAgCaXrcPk329Nq6FGSij8RKw==}
|
|
8985
|
-
|
|
8986
8974
|
zova-module-a-zova@5.1.108:
|
|
8987
8975
|
resolution: {integrity: sha512-K6ZmbuKPScDXOmmNuDxrMtoo3n+YTgbf9BSVJcen++CVuHPXNSdr+kQTpOa+B12O+PxUKCfmwwCSh7T9RrjiEA==}
|
|
8988
8976
|
|
|
@@ -8992,15 +8980,9 @@ packages:
|
|
|
8992
8980
|
zova-module-rest-resource@5.1.55:
|
|
8993
8981
|
resolution: {integrity: sha512-Kk3oJIcxM5EbeTLl+ucJSeI2kT0We8YilXBaX8Z7QWCbZ0fHoQDy/Ac4YsVSWIXUrC2SQ267+nMl3sHXnE9G0Q==}
|
|
8994
8982
|
|
|
8995
|
-
zova-suite-a-zova@5.1.164:
|
|
8996
|
-
resolution: {integrity: sha512-0o/mBzx6fiPsPIKEltIRW2Hfntza2Hc8q/n7y+BQYXdoNN3WdvDpE6XrbG5Lu/+AXlHn42n49bgEgawNSYb/Xw==}
|
|
8997
|
-
|
|
8998
8983
|
zova-suite-a-zova@5.1.165:
|
|
8999
8984
|
resolution: {integrity: sha512-hXjFEx9MXrtvPgAv28VF2UbgM45hzz7B7ZAsElJloBNWB3zyz2HUHYxNWDbCrrKfrw5zM3Mbr9i+dzyy3/6LQw==}
|
|
9000
8985
|
|
|
9001
|
-
zova@5.1.165:
|
|
9002
|
-
resolution: {integrity: sha512-oz67Qkzx+u/xE3hVOkIDEFFr7IwImfWIurmxdSpWA3UuzC+9bVDaDu3CDj/3l0n/0LIYnjmbff66k5gKikYWzg==}
|
|
9003
|
-
|
|
9004
8986
|
zova@5.1.166:
|
|
9005
8987
|
resolution: {integrity: sha512-2qh4Na6G8JYHWIyX7+NNfMLzzgHsheQFUgeH6KVsMp66kxpdR9YSr5Ivz+dJepthtmnlCB7R+WWczhURx4wYYA==}
|
|
9006
8988
|
|
|
@@ -15081,37 +15063,6 @@ snapshots:
|
|
|
15081
15063
|
|
|
15082
15064
|
yocto-queue@0.1.0: {}
|
|
15083
15065
|
|
|
15084
|
-
zova-core@5.1.91(typescript@5.9.3):
|
|
15085
|
-
dependencies:
|
|
15086
|
-
'@cabloy/compose': link:packages-utils/compose
|
|
15087
|
-
'@cabloy/extend': link:packages-utils/extend
|
|
15088
|
-
'@cabloy/json5': link:packages-utils/json5
|
|
15089
|
-
'@cabloy/localeutil': link:packages-utils/localeutil
|
|
15090
|
-
'@cabloy/logger': 1.1.25
|
|
15091
|
-
'@cabloy/module-info': 2.0.3
|
|
15092
|
-
'@cabloy/utils': link:packages-utils/utils
|
|
15093
|
-
'@cabloy/vue-compiler-sfc': 3.5.14
|
|
15094
|
-
'@cabloy/vue-reactivity': 3.5.16
|
|
15095
|
-
'@cabloy/vue-router': 4.4.18(vue@3.5.43(typescript@5.9.3))
|
|
15096
|
-
'@cabloy/vue-runtime-core': 3.5.57
|
|
15097
|
-
'@cabloy/vue-runtime-dom': 3.5.13
|
|
15098
|
-
'@cabloy/vue-server-renderer': 3.5.18(vue@3.5.43(typescript@5.9.3))
|
|
15099
|
-
'@cabloy/word-utils': 2.1.14
|
|
15100
|
-
'@cabloy/zod-errors-custom': link:packages-utils/zod-errors-custom
|
|
15101
|
-
'@cabloy/zod-openapi': link:packages-utils/zod-openapi
|
|
15102
|
-
'@cabloy/zod-query': link:packages-utils/zod-query
|
|
15103
|
-
'@types/js-cookie': 3.0.6
|
|
15104
|
-
'@types/ms': 2.1.0
|
|
15105
|
-
'@vue/shared': 3.5.36
|
|
15106
|
-
deep-equal: 2.2.3
|
|
15107
|
-
ms: 2.1.3
|
|
15108
|
-
reflect-metadata: 0.2.2
|
|
15109
|
-
vue: 3.5.43(typescript@5.9.3)
|
|
15110
|
-
vue-plugin-render-freeze: 2.0.4(vue@3.5.43(typescript@5.9.3))
|
|
15111
|
-
zod: '@cabloy/zod@4.3.8'
|
|
15112
|
-
transitivePeerDependencies:
|
|
15113
|
-
- typescript
|
|
15114
|
-
|
|
15115
15066
|
zova-core@5.1.92(patch_hash=144450bd7a567a6067e5857c0cf4c780981b7e90bc48745c09e1696a9b6f1b97)(typescript@5.9.3):
|
|
15116
15067
|
dependencies:
|
|
15117
15068
|
'@cabloy/compose': link:packages-utils/compose
|
|
@@ -15143,17 +15094,6 @@ snapshots:
|
|
|
15143
15094
|
transitivePeerDependencies:
|
|
15144
15095
|
- typescript
|
|
15145
15096
|
|
|
15146
|
-
zova-jsx@1.1.91(typescript@5.9.3):
|
|
15147
|
-
dependencies:
|
|
15148
|
-
'@cabloy/compose': link:packages-utils/compose
|
|
15149
|
-
'@cabloy/utils': link:packages-utils/utils
|
|
15150
|
-
'@cabloy/word-utils': 2.1.14
|
|
15151
|
-
typestyle: 2.4.0
|
|
15152
|
-
vue: 3.5.43(typescript@5.9.3)
|
|
15153
|
-
zova-core: 5.1.91(typescript@5.9.3)
|
|
15154
|
-
transitivePeerDependencies:
|
|
15155
|
-
- typescript
|
|
15156
|
-
|
|
15157
15097
|
zova-jsx@1.1.92(typescript@5.9.3):
|
|
15158
15098
|
dependencies:
|
|
15159
15099
|
'@cabloy/compose': link:packages-utils/compose
|
|
@@ -15226,8 +15166,6 @@ snapshots:
|
|
|
15226
15166
|
|
|
15227
15167
|
zova-module-a-pay@5.0.9: {}
|
|
15228
15168
|
|
|
15229
|
-
zova-module-a-router@5.1.40: {}
|
|
15230
|
-
|
|
15231
15169
|
zova-module-a-router@5.1.41: {}
|
|
15232
15170
|
|
|
15233
15171
|
zova-module-a-routerstack@5.1.29: {}
|
|
@@ -15267,22 +15205,6 @@ snapshots:
|
|
|
15267
15205
|
'@cabloy/zod-query': link:packages-utils/zod-query
|
|
15268
15206
|
zod: '@cabloy/zod@4.3.8'
|
|
15269
15207
|
|
|
15270
|
-
zova-module-a-zova@5.1.107(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3)):
|
|
15271
|
-
dependencies:
|
|
15272
|
-
'@cabloy/compose': link:packages-utils/compose
|
|
15273
|
-
'@cabloy/deps': link:packages-utils/deps
|
|
15274
|
-
'@cabloy/json5': link:packages-utils/json5
|
|
15275
|
-
'@cabloy/module-info': 2.0.3
|
|
15276
|
-
'@cabloy/utils': link:packages-utils/utils
|
|
15277
|
-
'@cabloy/vue-router': 4.4.18(vue@3.5.43(typescript@5.9.3))
|
|
15278
|
-
'@cabloy/word-utils': 2.1.14
|
|
15279
|
-
defu: 6.1.7
|
|
15280
|
-
luxon: 3.7.2
|
|
15281
|
-
zova-jsx: 1.1.91(typescript@5.9.3)
|
|
15282
|
-
transitivePeerDependencies:
|
|
15283
|
-
- typescript
|
|
15284
|
-
- vue
|
|
15285
|
-
|
|
15286
15208
|
zova-module-a-zova@5.1.108(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3)):
|
|
15287
15209
|
dependencies:
|
|
15288
15210
|
'@cabloy/compose': link:packages-utils/compose
|
|
@@ -15303,39 +15225,6 @@ snapshots:
|
|
|
15303
15225
|
|
|
15304
15226
|
zova-module-rest-resource@5.1.55: {}
|
|
15305
15227
|
|
|
15306
|
-
zova-suite-a-zova@5.1.164(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3)):
|
|
15307
|
-
dependencies:
|
|
15308
|
-
zova-module-a-api: 5.1.22
|
|
15309
|
-
zova-module-a-app: 5.1.26
|
|
15310
|
-
zova-module-a-bean: 5.1.36
|
|
15311
|
-
zova-module-a-behavior: 5.1.26
|
|
15312
|
-
zova-module-a-behaviors: 5.1.22
|
|
15313
|
-
zova-module-a-command: 5.1.35
|
|
15314
|
-
zova-module-a-fetch: 5.1.25
|
|
15315
|
-
zova-module-a-form: 5.1.51(vue@3.5.43(typescript@5.9.3))
|
|
15316
|
-
zova-module-a-icon: 5.1.27
|
|
15317
|
-
zova-module-a-interceptor: 5.1.31
|
|
15318
|
-
zova-module-a-logger: 5.1.28
|
|
15319
|
-
zova-module-a-meta: 5.1.22
|
|
15320
|
-
zova-module-a-model: 5.1.37(vue@3.5.43(typescript@5.9.3))
|
|
15321
|
-
zova-module-a-openapi: 5.1.54
|
|
15322
|
-
zova-module-a-router: 5.1.40
|
|
15323
|
-
zova-module-a-routerstack: 5.1.29
|
|
15324
|
-
zova-module-a-routertabs: 5.1.34
|
|
15325
|
-
zova-module-a-ssr: 5.1.40
|
|
15326
|
-
zova-module-a-ssrhmr: 5.1.23
|
|
15327
|
-
zova-module-a-ssrserver: 5.1.26
|
|
15328
|
-
zova-module-a-style: 5.1.35
|
|
15329
|
-
zova-module-a-table: 5.1.43(vue@3.5.43(typescript@5.9.3))
|
|
15330
|
-
zova-module-a-zod: 5.1.37
|
|
15331
|
-
zova-module-a-zova: 5.1.107(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3))
|
|
15332
|
-
transitivePeerDependencies:
|
|
15333
|
-
- '@vue/composition-api'
|
|
15334
|
-
- debug
|
|
15335
|
-
- supports-color
|
|
15336
|
-
- typescript
|
|
15337
|
-
- vue
|
|
15338
|
-
|
|
15339
15228
|
zova-suite-a-zova@5.1.165(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3)):
|
|
15340
15229
|
dependencies:
|
|
15341
15230
|
zova-module-a-api: 5.1.22
|
|
@@ -15369,17 +15258,6 @@ snapshots:
|
|
|
15369
15258
|
- typescript
|
|
15370
15259
|
- vue
|
|
15371
15260
|
|
|
15372
|
-
zova@5.1.165(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3)):
|
|
15373
|
-
dependencies:
|
|
15374
|
-
zova-core: 5.1.91(typescript@5.9.3)
|
|
15375
|
-
zova-suite-a-zova: 5.1.164(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3))
|
|
15376
|
-
transitivePeerDependencies:
|
|
15377
|
-
- '@vue/composition-api'
|
|
15378
|
-
- debug
|
|
15379
|
-
- supports-color
|
|
15380
|
-
- typescript
|
|
15381
|
-
- vue
|
|
15382
|
-
|
|
15383
15261
|
zova@5.1.166(typescript@5.9.3)(vue@3.5.43(typescript@5.9.3)):
|
|
15384
15262
|
dependencies:
|
|
15385
15263
|
zova-core: 5.1.92(patch_hash=144450bd7a567a6067e5857c0cf4c780981b7e90bc48745c09e1696a9b6f1b97)(typescript@5.9.3)
|
|
@@ -601,7 +601,7 @@ export class ServiceAccount extends BeanBase {
|
|
|
601
601
|
url.password ||
|
|
602
602
|
url.search ||
|
|
603
603
|
url.hash ||
|
|
604
|
-
this.bean.security.checkOriginExact(url.origin, this.
|
|
604
|
+
this.bean.security.checkOriginExact(url.origin, this.app.util.host) !== url.origin
|
|
605
605
|
) {
|
|
606
606
|
this.app.throw(503, `account ${purpose} consumer URL is invalid`);
|
|
607
607
|
}
|
|
@@ -248,21 +248,38 @@ describe('accountPasswordReset.test.ts', { concurrency: false }, () => {
|
|
|
248
248
|
}
|
|
249
249
|
});
|
|
250
250
|
|
|
251
|
-
it('
|
|
251
|
+
it('uses the canonical host for an exact same-origin consumer without a whitelist entry', async () => {
|
|
252
252
|
let fixture: IAccountPasswordResetFixture | undefined;
|
|
253
253
|
let restoreConfig: (() => void) | undefined;
|
|
254
|
+
let serve: typeof app.config.server.serve | undefined;
|
|
255
|
+
let servePrevious: { protocol?: string; host?: string } | undefined;
|
|
254
256
|
try {
|
|
255
257
|
fixture = await createFixture({ simpleAuth: true });
|
|
256
258
|
restoreConfig = await configurePasswordReset([]);
|
|
259
|
+
await app.bean.executor.mockCtx(async () => {
|
|
260
|
+
serve = app.ctx.config.server.serve;
|
|
261
|
+
servePrevious = { ...serve };
|
|
262
|
+
(serve as any).host = 'canonical.example.test';
|
|
263
|
+
});
|
|
257
264
|
|
|
258
265
|
const sameOriginConsumerUrl = await app.bean.executor.mockCtx(async () => {
|
|
259
|
-
return `${app.ctx.protocol}://${app.
|
|
266
|
+
return `${app.ctx.protocol}://${app.util.host}/home/user/password-reset`;
|
|
260
267
|
});
|
|
261
268
|
const issued = await issuePasswordResetLink(fixture, sameOriginConsumerUrl);
|
|
262
269
|
assert.equal(issued.origin, new URL(sameOriginConsumerUrl).origin);
|
|
263
270
|
assert.equal(issued.path, '/home/user/password-reset');
|
|
264
271
|
assert.equal(issued.search, `?token=${issued.token}`);
|
|
272
|
+
|
|
273
|
+
await clearPasswordResetState(fixture.userId);
|
|
274
|
+
await clearPasswordResetRecipientCooldown(fixture.email);
|
|
275
|
+
const requestOriginConsumerUrl = await app.bean.executor.mockCtx(async () => {
|
|
276
|
+
return `${app.ctx.protocol}://${app.ctx.host}/home/user/password-reset`;
|
|
277
|
+
});
|
|
278
|
+
await requestPasswordReset(fixture.email, requestOriginConsumerUrl);
|
|
279
|
+
await assertNoPasswordResetState(fixture.userId);
|
|
280
|
+
await assertNoPasswordResetRecipientCooldown(fixture.email);
|
|
265
281
|
} finally {
|
|
282
|
+
if (serve && servePrevious) Object.assign(serve, servePrevious);
|
|
266
283
|
restoreConfig?.();
|
|
267
284
|
if (fixture) await removeFixture(fixture);
|
|
268
285
|
}
|
|
@@ -706,9 +723,11 @@ async function assertNoPasswordResetRecipientCooldown(email: string) {
|
|
|
706
723
|
}
|
|
707
724
|
|
|
708
725
|
async function clearPasswordResetState(userId: string): Promise<void> {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
726
|
+
await app.bean.executor.mockCtx(async () => {
|
|
727
|
+
const digest = await app.scope('home-user').cacheRedis.passwordResetCurrent.get(userId as any);
|
|
728
|
+
if (digest) await app.scope('home-user').cacheRedis.passwordReset.del(digest);
|
|
729
|
+
await app.scope('home-user').cacheRedis.passwordResetCurrent.del(userId as any);
|
|
730
|
+
});
|
|
712
731
|
}
|
|
713
732
|
|
|
714
733
|
async function assertNoPasswordResetState(userId: string, digest?: string): Promise<void> {
|
|
@@ -453,21 +453,36 @@ describe('accountPasswordSet.test.ts', { concurrency: false, sequential: true },
|
|
|
453
453
|
}
|
|
454
454
|
});
|
|
455
455
|
|
|
456
|
-
it('
|
|
456
|
+
it('uses the canonical host for an exact same-origin consumer without a whitelist entry', async () => {
|
|
457
457
|
let fixture: IAccountPasswordSetFixture | undefined;
|
|
458
458
|
let restoreConfig: (() => void) | undefined;
|
|
459
|
+
let serve: typeof app.config.server.serve | undefined;
|
|
460
|
+
let servePrevious: { protocol?: string; host?: string } | undefined;
|
|
459
461
|
try {
|
|
460
462
|
fixture = await createFixture();
|
|
461
463
|
restoreConfig = await configurePasswordSet([]);
|
|
464
|
+
await app.bean.executor.mockCtx(async () => {
|
|
465
|
+
serve = app.ctx.config.server.serve;
|
|
466
|
+
servePrevious = { ...serve };
|
|
467
|
+
(serve as any).host = 'canonical.example.test';
|
|
468
|
+
});
|
|
462
469
|
|
|
463
470
|
const sameOriginConsumerUrl = await app.bean.executor.mockCtx(async () => {
|
|
464
|
-
return `${app.ctx.protocol}://${app.
|
|
471
|
+
return `${app.ctx.protocol}://${app.util.host}/home/user/password-set`;
|
|
465
472
|
});
|
|
466
473
|
const issued = await issuePasswordSetLink(fixture, sameOriginConsumerUrl);
|
|
467
474
|
assert.equal(issued.origin, new URL(sameOriginConsumerUrl).origin);
|
|
468
475
|
assert.equal(issued.path, '/home/user/password-set');
|
|
469
476
|
assert.equal(issued.search, `?token=${issued.token}`);
|
|
477
|
+
|
|
478
|
+
await clearPasswordSetState(fixture.userId);
|
|
479
|
+
const requestOriginConsumerUrl = await app.bean.executor.mockCtx(async () => {
|
|
480
|
+
return `${app.ctx.protocol}://${app.ctx.host}/home/user/password-set`;
|
|
481
|
+
});
|
|
482
|
+
await issuePasswordSetLinkRejected(fixture, requestOriginConsumerUrl);
|
|
483
|
+
await assertNoPasswordSetState(fixture.userId);
|
|
470
484
|
} finally {
|
|
485
|
+
if (serve && servePrevious) Object.assign(serve, servePrevious);
|
|
471
486
|
restoreConfig?.();
|
|
472
487
|
if (fixture) await removeFixture(fixture);
|
|
473
488
|
}
|
|
@@ -784,9 +799,11 @@ async function getCacheTtl(cacheName: 'passwordSet' | 'passwordSetCurrent', key:
|
|
|
784
799
|
}
|
|
785
800
|
|
|
786
801
|
async function clearPasswordSetState(userId: string): Promise<void> {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
802
|
+
await app.bean.executor.mockCtx(async () => {
|
|
803
|
+
const digest = await app.scope('home-user').cacheRedis.passwordSetCurrent.get(userId);
|
|
804
|
+
if (digest) await app.scope('home-user').cacheRedis.passwordSet.del(digest);
|
|
805
|
+
await app.scope('home-user').cacheRedis.passwordSetCurrent.del(userId);
|
|
806
|
+
});
|
|
790
807
|
}
|
|
791
808
|
|
|
792
809
|
async function assertNoPasswordSetState(userId: string, digest?: string): Promise<void> {
|