@faststore/core 3.100.1 → 3.100.3
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/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +48 -48
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/config.json +3 -3
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/prerender-manifest.js +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/react-loadable-manifest.json +8 -8
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/948.js +2 -2
- package/.next/server/functions-config-manifest.json +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +2 -2
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/api/fs/password-protection/unlock.js +1 -0
- package/.next/server/pages/api/preview.js +1 -1
- package/.next/server/pages/en-US/404.html +2 -2
- package/.next/server/pages/en-US/500.html +2 -2
- package/.next/server/pages/en-US/checkout.html +2 -2
- package/.next/server/pages/en-US/login.html +2 -2
- package/.next/server/pages/en-US/{fs-auth-login.html → password-protection.html} +2 -2
- package/.next/server/pages/en-US/s.html +2 -2
- package/.next/server/pages/en-US.html +2 -2
- package/.next/server/pages-manifest.json +1 -1
- package/.next/server/src/middleware.js +33 -33
- package/.next/server/src/middleware.js.map +1 -1
- package/.next/static/0OKcQtIHO8diwBsczup15/_buildManifest.js +1 -0
- package/.next/static/chunks/{2927.23bae2c79f0ac0f3.js → 2927.5a79877943a6bf7c.js} +1 -1
- package/.next/static/chunks/3802.904f302bf009f795.js +1 -0
- package/.next/static/chunks/9380.217554eeecd9b37f.js +1 -0
- package/.next/static/chunks/{UIToast.de15325248043ce5.js → UIToast.19a8664c01a00d3a.js} +1 -1
- package/.next/static/chunks/main-a2d1cfe626f2fef1.js +1 -0
- package/.next/static/chunks/pages/{[...slug]-dc8a395a43b081f1.js → [...slug]-cf9e3bf4febd21c3.js} +1 -1
- package/.next/static/chunks/pages/password-protection-8dece47ea041d372.js +1 -0
- package/.next/static/chunks/webpack-25c67512e1907efd.js +1 -0
- package/.next/static/css/033b9397a0c0cf71.css +1 -0
- package/.next/trace +156 -156
- package/.turbo/turbo-build.log +17 -17
- package/.turbo/turbo-test.log +8 -8
- package/CHANGELOG.md +12 -0
- package/package.json +3 -3
- package/src/middleware.ts +14 -13
- package/src/pages/api/fs/{auth/login.ts → password-protection/unlock.ts} +4 -4
- package/src/pages/{fs-auth-login → password-protection}/index.tsx +10 -7
- package/src/pages/{fs-auth-login/fs-auth-login.module.scss → password-protection/password-protection.module.scss} +1 -1
- package/src/server/content/service.ts +33 -2
- package/src/server/{authentication-service.ts → password-protection-service.ts} +22 -18
- package/src/utils/{loginResponse.ts → unlockResponse.ts} +7 -2
- package/test/server/{authentication-service.test.ts → password-protection-service.test.ts} +71 -59
- package/.next/server/pages/api/fs/auth/login.js +0 -1
- package/.next/static/Lk9fl1r-H5eeVzeqYkA-Y/_buildManifest.js +0 -1
- package/.next/static/chunks/349.b3b38e1e9f719dda.js +0 -1
- package/.next/static/chunks/3802.5e8b0b689eacc0f8.js +0 -1
- package/.next/static/chunks/main-083a618181bb5fbb.js +0 -1
- package/.next/static/chunks/pages/fs-auth-login-ba2d1b3ef0ef0415.js +0 -1
- package/.next/static/chunks/webpack-ff85816fb58111fa.js +0 -1
- package/.next/static/css/3bd4edd425711792.css +0 -1
- /package/.next/server/pages/api/fs/{auth/login.js.nft.json → password-protection/unlock.js.nft.json} +0 -0
- /package/.next/server/pages/{fs-auth-login.js.nft.json → password-protection.js.nft.json} +0 -0
- /package/.next/static/{Lk9fl1r-H5eeVzeqYkA-Y → 0OKcQtIHO8diwBsczup15}/_ssgManifest.js +0 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.100.
|
|
2
|
+
> @faststore/core@3.100.2 prebuild /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> na run partytown && na run generate
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @faststore/core@3.100.
|
|
6
|
+
> @faststore/core@3.100.2 partytown /home/runner/work/faststore/faststore/packages/core
|
|
7
7
|
> partytown copylib ./public/~partytown
|
|
8
8
|
|
|
9
9
|
Partytown lib copied to: /home/runner/work/faststore/faststore/packages/core/public/~partytown
|
|
10
10
|
|
|
11
|
-
> @faststore/core@3.100.
|
|
11
|
+
> @faststore/core@3.100.2 generate /home/runner/work/faststore/faststore/packages/core
|
|
12
12
|
> na run generate:schema && na run generate:codegen && na run format:generated
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
> @faststore/core@3.100.
|
|
15
|
+
> @faststore/core@3.100.2 generate:schema /home/runner/work/faststore/faststore/packages/core
|
|
16
16
|
> tsx src/server/generator/generateGraphQLSchemaFile.ts
|
|
17
17
|
|
|
18
18
|
Schema GraphQL file generated successfully
|
|
19
19
|
|
|
20
|
-
> @faststore/core@3.100.
|
|
20
|
+
> @faststore/core@3.100.2 generate:codegen /home/runner/work/faststore/faststore/packages/core
|
|
21
21
|
> graphql-codegen
|
|
22
22
|
|
|
23
23
|
[STARTED] Parse Configuration
|
|
@@ -37,11 +37,11 @@ Running lifecycle hook "afterStart" scripts...
|
|
|
37
37
|
[CLI] Loading Documents
|
|
38
38
|
[CLI] Generating output
|
|
39
39
|
|
|
40
|
-
> @faststore/core@3.100.
|
|
40
|
+
> @faststore/core@3.100.2 format:generated /home/runner/work/faststore/faststore/packages/core
|
|
41
41
|
> prettier --write "@generated/**/*.{ts,js,tsx,jsx,json}" --loglevel error
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
> @faststore/core@3.100.
|
|
44
|
+
> @faststore/core@3.100.2 build /home/runner/work/faststore/faststore/packages/core
|
|
45
45
|
> next build
|
|
46
46
|
|
|
47
47
|
⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache
|
|
@@ -83,9 +83,9 @@ Learn more: https://nextjs.org/docs/api-reference/edge-runtime
|
|
|
83
83
|
|
|
84
84
|
Import trace for requested module:
|
|
85
85
|
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/lib/deflate.js
|
|
86
|
-
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/jwe/flattened/
|
|
86
|
+
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js
|
|
87
87
|
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/index.js
|
|
88
|
-
./src/server/
|
|
88
|
+
./src/server/password-protection-service.ts
|
|
89
89
|
|
|
90
90
|
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/lib/deflate.js
|
|
91
91
|
A Node.js API is used (DecompressionStream at line: 25) which is not supported in the Edge Runtime.
|
|
@@ -93,17 +93,17 @@ Learn more: https://nextjs.org/docs/api-reference/edge-runtime
|
|
|
93
93
|
|
|
94
94
|
Import trace for requested module:
|
|
95
95
|
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/lib/deflate.js
|
|
96
|
-
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/jwe/flattened/
|
|
96
|
+
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js
|
|
97
97
|
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/index.js
|
|
98
|
-
./src/server/
|
|
98
|
+
./src/server/password-protection-service.ts
|
|
99
99
|
|
|
100
100
|
Collecting page data ...
|
|
101
101
|
Generating static pages (0/8) ...
|
|
102
102
|
|
|
103
103
|
Generating static pages (2/8)
|
|
104
104
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
105
|
+
Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Content documentation at https://developers.vtex.com/docs/guides/faststore/dynamic-content-overview for mapping the page and the corresponding data-fetching function.
|
|
105
106
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
106
107
|
|
|
107
108
|
Generating static pages (4/8)
|
|
108
|
-
Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Content documentation at https://developers.vtex.com/docs/guides/faststore/dynamic-content-overview for mapping the page and the corresponding data-fetching function.
|
|
109
109
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
110
110
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
111
111
|
|
|
112
112
|
Generating static pages (6/8)
|
|
@@ -123,16 +123,16 @@ Route (pages) Size First Load JS
|
|
|
123
123
|
├ └ css/54cedf4b65e5863f.css 16.7 kB
|
|
124
124
|
├ ○ /404 1.58 kB 160 kB
|
|
125
125
|
├ ● /500 1.58 kB 160 kB
|
|
126
|
-
├ λ /api/fs/auth/login 0 B 109 kB
|
|
127
126
|
├ λ /api/fs/logout 0 B 109 kB
|
|
127
|
+
├ λ /api/fs/password-protection/unlock 0 B 109 kB
|
|
128
128
|
├ λ /api/graphql 0 B 109 kB
|
|
129
129
|
├ λ /api/health/live 0 B 109 kB
|
|
130
130
|
├ λ /api/health/ready 0 B 109 kB
|
|
131
131
|
├ λ /api/preview 0 B 109 kB
|
|
132
132
|
├ ● /checkout 750 B 159 kB
|
|
133
|
-
├ ○ /fs-auth-login 2.17 kB 111 kB
|
|
134
|
-
├ └ css/3bd4edd425711792.css 3.2 kB
|
|
135
133
|
├ ● /login 1.7 kB 160 kB
|
|
134
|
+
├ ○ /password-protection 2.18 kB 111 kB
|
|
135
|
+
├ └ css/033b9397a0c0cf71.css 3.2 kB
|
|
136
136
|
├ λ /pvt/account 247 B 109 kB
|
|
137
137
|
├ ● /pvt/account/[...unknown] 287 B 109 kB
|
|
138
138
|
├ λ /pvt/account/403 3 kB 161 kB
|
|
@@ -152,9 +152,9 @@ Route (pages) Size First Load JS
|
|
|
152
152
|
└ ● /s 3.35 kB 176 kB
|
|
153
153
|
+ First Load JS shared by all 118 kB
|
|
154
154
|
├ chunks/framework-d514426edf885c68.js 45.4 kB
|
|
155
|
-
├ chunks/main-
|
|
155
|
+
├ chunks/main-a2d1cfe626f2fef1.js 33.4 kB
|
|
156
156
|
├ chunks/pages/_app-35e8dda638ee2672.js 26.6 kB
|
|
157
|
-
├ chunks/webpack-
|
|
157
|
+
├ chunks/webpack-25c67512e1907efd.js 3.9 kB
|
|
158
158
|
└ css/146a8678babc61bf.css 9.2 kB
|
|
159
159
|
|
|
160
160
|
ƒ Middleware 44.8 kB
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.100.
|
|
2
|
+
> @faststore/core@3.100.2 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> jest
|
|
4
4
|
|
|
5
|
-
PASS test/utils/clearCookies.test.ts (
|
|
6
|
-
PASS test/server/authentication-service.test.ts (15.26 s)
|
|
7
|
-
PASS test/utils/cookieCacheBusting.test.ts (14.803 s)
|
|
5
|
+
PASS test/utils/clearCookies.test.ts (9.746 s)
|
|
8
6
|
PASS test/utils/multipleTemplates.test.ts
|
|
9
|
-
PASS test/
|
|
7
|
+
PASS test/server/password-protection-service.test.ts (16.656 s)
|
|
8
|
+
PASS test/utils/cookieCacheBusting.test.ts (15.853 s)
|
|
10
9
|
PASS test/server/cms/global.test.ts
|
|
10
|
+
PASS test/utils/validateSessionRefreshToken.test.ts
|
|
11
11
|
PASS test/utils/isLocalHost.test.ts
|
|
12
|
+
PASS test/server/cms/index.test.ts
|
|
12
13
|
PASS test/utils/isLocalHost.browser.test.ts
|
|
13
|
-
PASS test/server/
|
|
14
|
-
PASS test/server/index.test.ts (10.14 s)
|
|
14
|
+
PASS test/server/index.test.ts (11.788 s)
|
|
15
15
|
|
|
16
16
|
Test Suites: 10 passed, 10 total
|
|
17
17
|
Tests: 85 passed, 85 total
|
|
18
18
|
Snapshots: 0 total
|
|
19
|
-
Time:
|
|
19
|
+
Time: 27.32 s
|
|
20
20
|
Ran all test suites.
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [3.100.3](https://github.com/vtex/faststore/compare/v3.100.2...v3.100.3) (2026-06-30)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- align password-protection vocabulary in v3 (unlock, not login) ([#3404](https://github.com/vtex/faststore/issues/3404)) ([30222fc](https://github.com/vtex/faststore/commit/30222fcde2b180eb3ded421949a2359917ba53d4)), closes [#3276](https://github.com/vtex/faststore/issues/3276)
|
|
11
|
+
|
|
12
|
+
## [3.100.2](https://github.com/vtex/faststore/compare/v3.100.1...v3.100.2) (2026-06-11)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- paginate listEntries with scroll ([#3384](https://github.com/vtex/faststore/issues/3384)) ([83fdae8](https://github.com/vtex/faststore/commit/83fdae826f8fd3e1f739887b21b529598f325cb6))
|
|
17
|
+
|
|
6
18
|
## [3.100.1](https://github.com/vtex/faststore/compare/v3.100.0...v3.100.1) (2026-06-08)
|
|
7
19
|
|
|
8
20
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "3.100.
|
|
3
|
+
"version": "3.100.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"@parcel/watcher": "^2.4.0",
|
|
76
76
|
"@types/react": "^18.2.42",
|
|
77
77
|
"@vtex/client-cms": "^0.2.16",
|
|
78
|
-
"@vtex/client-cp": "0.
|
|
78
|
+
"@vtex/client-cp": "0.6.0",
|
|
79
79
|
"@vtex/prettier-config": "1.0.0",
|
|
80
80
|
"autoprefixer": "^10.4.0",
|
|
81
81
|
"cookie": "^0.7.0",
|
|
@@ -127,5 +127,5 @@
|
|
|
127
127
|
"ts-jest": "29.1.1",
|
|
128
128
|
"typescript": "5.3.2"
|
|
129
129
|
},
|
|
130
|
-
"gitHead": "
|
|
130
|
+
"gitHead": "bf4812f3e3a53108f22ab987098b74f7eed9bfa3"
|
|
131
131
|
}
|
package/src/middleware.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Middleware is always active. It runs:
|
|
3
|
-
* 1. Password protection (
|
|
3
|
+
* 1. Password protection (PasswordProtectionService) — when applicable (default/custom domains per env).
|
|
4
4
|
* 2. Redirects — only when ENABLE_REDIRECTS_MIDDLEWARE is set at runtime.
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ import { NextResponse } from 'next/server'
|
|
|
8
8
|
import type { NextRequest } from 'next/server'
|
|
9
9
|
import storeConfig from 'discovery.config'
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { PasswordProtectionService } from './server/password-protection-service'
|
|
12
12
|
|
|
13
13
|
type Redirect = {
|
|
14
14
|
from: string
|
|
@@ -31,19 +31,20 @@ const redirectsClient = new DynamoRedirectsClient()
|
|
|
31
31
|
export async function middleware(request: NextRequest) {
|
|
32
32
|
const path = request.nextUrl.pathname
|
|
33
33
|
|
|
34
|
-
let
|
|
35
|
-
ReturnType<
|
|
34
|
+
let storeProtectionResult: Awaited<
|
|
35
|
+
ReturnType<PasswordProtectionService['checkStoreProtection']>
|
|
36
36
|
>
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
|
-
const
|
|
40
|
-
|
|
39
|
+
const protectionService = new PasswordProtectionService()
|
|
40
|
+
storeProtectionResult =
|
|
41
|
+
await protectionService.checkStoreProtection(request)
|
|
41
42
|
} catch {
|
|
42
43
|
return NextResponse.error()
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
if (
|
|
46
|
-
return
|
|
46
|
+
if (storeProtectionResult.response.status !== 200) {
|
|
47
|
+
return storeProtectionResult.response
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
if (process.env.ENABLE_REDIRECTS_MIDDLEWARE === 'true') {
|
|
@@ -54,7 +55,7 @@ export async function middleware(request: NextRequest) {
|
|
|
54
55
|
const redirectStatusCode = redirect.type === 'permanent' ? 301 : 302
|
|
55
56
|
const response = NextResponse.redirect(redirectUrl, redirectStatusCode)
|
|
56
57
|
|
|
57
|
-
for (const cookie of
|
|
58
|
+
for (const cookie of storeProtectionResult.response.cookies.getAll()) {
|
|
58
59
|
response.cookies.set(cookie)
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -67,7 +68,7 @@ export async function middleware(request: NextRequest) {
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
return
|
|
71
|
+
return storeProtectionResult.response
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
export const config = {
|
|
@@ -75,13 +76,13 @@ export const config = {
|
|
|
75
76
|
/*
|
|
76
77
|
* Match all paths including `/`
|
|
77
78
|
* Exclude:
|
|
78
|
-
* - api (e.g. api/fs/
|
|
79
|
+
* - api (e.g. api/fs/password-protection/unlock)
|
|
79
80
|
* - _next/static, _next/image
|
|
80
81
|
* - favicon.ico
|
|
81
|
-
* -
|
|
82
|
+
* - password-protection (unlock page)
|
|
82
83
|
* - ~partytown (partytown scripts)
|
|
83
84
|
*/
|
|
84
85
|
'/',
|
|
85
|
-
'/((?!api|_next/static|_next/image|favicon.ico|
|
|
86
|
+
'/((?!api|_next/static|_next/image|favicon.ico|password-protection|~partytown).*)',
|
|
86
87
|
],
|
|
87
88
|
}
|
|
@@ -2,7 +2,7 @@ import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
|
|
|
2
2
|
|
|
3
3
|
import storeConfig from 'discovery.config'
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { UnlockResponse } from '../../../../utils/unlockResponse'
|
|
6
6
|
import {
|
|
7
7
|
sessionUrl,
|
|
8
8
|
passwordProtectionTimeouts,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
COOKIE_NAME,
|
|
12
12
|
TOKEN_TTL_SECONDS,
|
|
13
|
-
} from 'src/server/
|
|
13
|
+
} from 'src/server/password-protection-service'
|
|
14
14
|
|
|
15
15
|
interface WebOpsSessionPayload {
|
|
16
16
|
valid: boolean
|
|
@@ -36,9 +36,9 @@ const isWebOpsSessionPayload = (
|
|
|
36
36
|
)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const handler: NextApiHandler<
|
|
39
|
+
const handler: NextApiHandler<UnlockResponse> = async (
|
|
40
40
|
request: NextApiRequest,
|
|
41
|
-
response: NextApiResponse<
|
|
41
|
+
response: NextApiResponse<UnlockResponse>
|
|
42
42
|
) => {
|
|
43
43
|
if (request.method !== 'POST') {
|
|
44
44
|
response.status(405).end()
|
|
@@ -3,8 +3,8 @@ import Head from 'next/head'
|
|
|
3
3
|
import { useRouter } from 'next/router'
|
|
4
4
|
import { type FormEvent, useState } from 'react'
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import styles from './
|
|
6
|
+
import { isUnlockResponse } from '../../utils/unlockResponse'
|
|
7
|
+
import styles from './password-protection.module.scss'
|
|
8
8
|
|
|
9
9
|
export default function PasswordProtectionLogin() {
|
|
10
10
|
const router = useRouter()
|
|
@@ -21,7 +21,10 @@ export default function PasswordProtectionLogin() {
|
|
|
21
21
|
setError('')
|
|
22
22
|
|
|
23
23
|
try {
|
|
24
|
-
const url = new URL(
|
|
24
|
+
const url = new URL(
|
|
25
|
+
'/api/fs/password-protection/unlock',
|
|
26
|
+
globalThis.location.origin
|
|
27
|
+
)
|
|
25
28
|
url.searchParams.set('returnTo', returnTo)
|
|
26
29
|
|
|
27
30
|
const response = await fetch(url.toString(), {
|
|
@@ -32,7 +35,7 @@ export default function PasswordProtectionLogin() {
|
|
|
32
35
|
|
|
33
36
|
const data: unknown = await response.json()
|
|
34
37
|
|
|
35
|
-
if (!
|
|
38
|
+
if (!isUnlockResponse(data)) {
|
|
36
39
|
setError('Service temporarily unavailable')
|
|
37
40
|
return
|
|
38
41
|
}
|
|
@@ -50,7 +53,7 @@ export default function PasswordProtectionLogin() {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
return (
|
|
53
|
-
<div className={styles.
|
|
56
|
+
<div className={styles.fsPasswordProtection}>
|
|
54
57
|
<Head>
|
|
55
58
|
<meta name="robots" content="noindex,nofollow" />
|
|
56
59
|
</Head>
|
|
@@ -63,7 +66,7 @@ export default function PasswordProtectionLogin() {
|
|
|
63
66
|
|
|
64
67
|
<form className={styles.form} onSubmit={handleSubmit}>
|
|
65
68
|
<InputField
|
|
66
|
-
id="
|
|
69
|
+
id="password-protection-input"
|
|
67
70
|
label="Password"
|
|
68
71
|
type="password"
|
|
69
72
|
value={password}
|
|
@@ -81,7 +84,7 @@ export default function PasswordProtectionLogin() {
|
|
|
81
84
|
disabled={loading}
|
|
82
85
|
loading={loading}
|
|
83
86
|
>
|
|
84
|
-
|
|
87
|
+
Unlock
|
|
85
88
|
</Button>
|
|
86
89
|
</form>
|
|
87
90
|
</div>
|
|
@@ -46,8 +46,29 @@ export class ContentService {
|
|
|
46
46
|
|
|
47
47
|
if (isContentPlatformSource()) {
|
|
48
48
|
const serviceParams = this.convertOptionsToParams(options)
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// TODO: This should be temporary until the cp data-plane have a search engine.
|
|
50
|
+
const MAX_PAGES = 25
|
|
51
|
+
const allEntries: ContentEntry[] = []
|
|
52
|
+
let scroll: string | undefined
|
|
53
|
+
let pages = 0
|
|
54
|
+
|
|
55
|
+
do {
|
|
56
|
+
const result = await this.clientCP.listEntries(serviceParams, scroll)
|
|
57
|
+
allEntries.push(...result.entries)
|
|
58
|
+
const next = result.scroll ?? undefined
|
|
59
|
+
if (next && next === scroll) break
|
|
60
|
+
scroll = next
|
|
61
|
+
} while (scroll && ++pages < MAX_PAGES)
|
|
62
|
+
|
|
63
|
+
if (pages >= MAX_PAGES) {
|
|
64
|
+
console.warn('listEntries pagination hit MAX_PAGES cap', serviceParams)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return this.fillEntriesWithData(
|
|
68
|
+
allEntries,
|
|
69
|
+
serviceParams,
|
|
70
|
+
options.isPreview
|
|
71
|
+
)
|
|
51
72
|
}
|
|
52
73
|
return getCMSPage(options.cmsOptions)
|
|
53
74
|
}
|
|
@@ -60,6 +81,11 @@ export class ContentService {
|
|
|
60
81
|
const options = this.createContentOptions(plpParams)
|
|
61
82
|
|
|
62
83
|
if (isContentPlatformSource()) {
|
|
84
|
+
const directMatch = await this.getSingleContent<PLPContentType>(plpParams)
|
|
85
|
+
if (directMatch) {
|
|
86
|
+
return directMatch
|
|
87
|
+
}
|
|
88
|
+
|
|
63
89
|
const pages = (await this.getMultipleContent(plpParams)).data
|
|
64
90
|
if (!pages?.length) throw new MissingContentError(options.cmsOptions)
|
|
65
91
|
return findBestPLPTemplate(
|
|
@@ -79,6 +105,11 @@ export class ContentService {
|
|
|
79
105
|
const options = this.createContentOptions(pdpParams)
|
|
80
106
|
|
|
81
107
|
if (isContentPlatformSource()) {
|
|
108
|
+
const directMatch = await this.getSingleContent<PDPContentType>(pdpParams)
|
|
109
|
+
if (directMatch) {
|
|
110
|
+
return directMatch
|
|
111
|
+
}
|
|
112
|
+
|
|
82
113
|
const pages = (await this.getMultipleContent(pdpParams)).data
|
|
83
114
|
if (!pages.length) throw new MissingContentError(options.cmsOptions)
|
|
84
115
|
return findBestPDPTemplate(
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
passwordProtectionTimeouts,
|
|
13
13
|
} from './password-protection/webops-api'
|
|
14
14
|
|
|
15
|
-
export const COOKIE_NAME = '
|
|
15
|
+
export const COOKIE_NAME = '__fs_password_protection'
|
|
16
16
|
export const TOKEN_TTL_SECONDS = 10 * 60
|
|
17
17
|
/** How long to reuse the RSA public key fetched from WebOps */
|
|
18
18
|
const PUBLIC_KEY_CACHE_MS = 60 * 60 * 1000
|
|
@@ -25,7 +25,7 @@ interface TokenPayload {
|
|
|
25
25
|
exp?: number
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
interface
|
|
28
|
+
interface StoreProtectionResult {
|
|
29
29
|
response: NextResponse
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -73,7 +73,7 @@ export function resetPasswordProtectionPublicKeyCacheForTests(): void {
|
|
|
73
73
|
publicKeyCache = null
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
export class
|
|
76
|
+
export class PasswordProtectionService {
|
|
77
77
|
private readonly storeId: string
|
|
78
78
|
|
|
79
79
|
constructor() {
|
|
@@ -85,7 +85,9 @@ export class AuthenticationService {
|
|
|
85
85
|
return host.split(':')[0].toLowerCase()
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
async
|
|
88
|
+
async checkStoreProtection(
|
|
89
|
+
request: NextRequest
|
|
90
|
+
): Promise<StoreProtectionResult> {
|
|
89
91
|
if (!this.shouldCheckProtection(request)) {
|
|
90
92
|
return { response: NextResponse.next() }
|
|
91
93
|
}
|
|
@@ -104,7 +106,7 @@ export class AuthenticationService {
|
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
return await this.
|
|
109
|
+
return await this.handleProtectionCheck(request)
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
private shouldCheckProtection(request: NextRequest): boolean {
|
|
@@ -182,7 +184,7 @@ export class AuthenticationService {
|
|
|
182
184
|
request: NextRequest,
|
|
183
185
|
expiredToken: string,
|
|
184
186
|
payload: TokenPayload
|
|
185
|
-
): Promise<
|
|
187
|
+
): Promise<StoreProtectionResult> {
|
|
186
188
|
try {
|
|
187
189
|
const res = await fetch(renewUrl(), {
|
|
188
190
|
method: 'POST',
|
|
@@ -199,7 +201,7 @@ export class AuthenticationService {
|
|
|
199
201
|
|
|
200
202
|
if (data.valid && data.token) {
|
|
201
203
|
const response = NextResponse.next()
|
|
202
|
-
this.
|
|
204
|
+
this.setProtectionCookie(response, data.token)
|
|
203
205
|
|
|
204
206
|
return { response }
|
|
205
207
|
}
|
|
@@ -212,17 +214,19 @@ export class AuthenticationService {
|
|
|
212
214
|
return { response: NextResponse.next() }
|
|
213
215
|
}
|
|
214
216
|
|
|
215
|
-
return { response: this.
|
|
217
|
+
return { response: this.redirectToUnlockPage(request) }
|
|
216
218
|
}
|
|
217
219
|
|
|
218
|
-
private async
|
|
220
|
+
private async handleProtectionCheck(
|
|
221
|
+
request: NextRequest
|
|
222
|
+
): Promise<StoreProtectionResult> {
|
|
219
223
|
try {
|
|
220
224
|
const res = await fetch(protectionStatusUrl(), {
|
|
221
225
|
signal: AbortSignal.timeout(passwordProtectionTimeouts.defaultMs),
|
|
222
226
|
})
|
|
223
227
|
|
|
224
228
|
if (!res.ok) {
|
|
225
|
-
return { response: this.
|
|
229
|
+
return { response: this.redirectToUnlockPage(request) }
|
|
226
230
|
}
|
|
227
231
|
|
|
228
232
|
const status = await res.json()
|
|
@@ -231,7 +235,7 @@ export class AuthenticationService {
|
|
|
231
235
|
const response = NextResponse.next()
|
|
232
236
|
|
|
233
237
|
if (status.token) {
|
|
234
|
-
this.
|
|
238
|
+
this.setProtectionCookie(response, status.token)
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
return { response }
|
|
@@ -241,13 +245,13 @@ export class AuthenticationService {
|
|
|
241
245
|
return { response: NextResponse.next() }
|
|
242
246
|
}
|
|
243
247
|
|
|
244
|
-
return { response: this.
|
|
248
|
+
return { response: this.redirectToUnlockPage(request) }
|
|
245
249
|
} catch {
|
|
246
|
-
return { response: this.
|
|
250
|
+
return { response: this.redirectToUnlockPage(request) }
|
|
247
251
|
}
|
|
248
252
|
}
|
|
249
253
|
|
|
250
|
-
private
|
|
254
|
+
private setProtectionCookie(response: NextResponse, token: string): void {
|
|
251
255
|
response.cookies.set(COOKIE_NAME, token, {
|
|
252
256
|
httpOnly: true,
|
|
253
257
|
secure: true,
|
|
@@ -257,12 +261,12 @@ export class AuthenticationService {
|
|
|
257
261
|
})
|
|
258
262
|
}
|
|
259
263
|
|
|
260
|
-
private
|
|
261
|
-
const
|
|
264
|
+
private redirectToUnlockPage(request: NextRequest): NextResponse {
|
|
265
|
+
const unlockUrl = new URL('/password-protection', request.url)
|
|
262
266
|
const returnTo = `${request.nextUrl.pathname}${request.nextUrl.search}`
|
|
263
|
-
|
|
267
|
+
unlockUrl.searchParams.set('returnTo', returnTo)
|
|
264
268
|
|
|
265
|
-
const response = NextResponse.redirect(
|
|
269
|
+
const response = NextResponse.redirect(unlockUrl)
|
|
266
270
|
response.headers.set('Cache-Control', 'no-store')
|
|
267
271
|
|
|
268
272
|
return response
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface UnlockResponse {
|
|
2
2
|
success?: boolean
|
|
3
3
|
redirectUrl?: string
|
|
4
4
|
error?: string
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export const
|
|
7
|
+
export const isUnlockResponse = (data: unknown): data is UnlockResponse => {
|
|
8
8
|
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
|
|
9
9
|
return false
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const payload = data as Record<string, unknown>
|
|
13
|
+
const hasUnlockResponseField =
|
|
14
|
+
payload.success !== undefined ||
|
|
15
|
+
payload.redirectUrl !== undefined ||
|
|
16
|
+
payload.error !== undefined
|
|
13
17
|
|
|
14
18
|
return (
|
|
19
|
+
hasUnlockResponseField &&
|
|
15
20
|
(payload.success === undefined || typeof payload.success === 'boolean') &&
|
|
16
21
|
(payload.redirectUrl === undefined ||
|
|
17
22
|
typeof payload.redirectUrl === 'string') &&
|