@faststore/core 3.99.6 → 3.100.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/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +47 -40
- 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 +6 -6
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/3779.js +1 -0
- package/.next/server/chunks/7098.js +2 -2
- package/.next/server/chunks/83.js +1 -1
- package/.next/server/chunks/948.js +3 -3
- package/.next/server/chunks/{9984.js → UINavbarSlider.js} +1 -1
- package/.next/server/edge-runtime-webpack.js +24 -0
- package/.next/server/edge-runtime-webpack.js.map +1 -1
- package/.next/server/instrumentation.js.nft.json +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +27 -2
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.js +1 -1
- package/.next/server/pages/404.js.nft.json +1 -1
- package/.next/server/pages/500.js +1 -1
- package/.next/server/pages/500.js.nft.json +1 -1
- package/.next/server/pages/[...slug].js +1 -1
- package/.next/server/pages/[...slug].js.nft.json +1 -1
- package/.next/server/pages/[slug]/p.js +1 -1
- package/.next/server/pages/[slug]/p.js.nft.json +1 -1
- package/.next/server/pages/_app.js.nft.json +1 -1
- package/.next/server/pages/_document.js.nft.json +1 -1
- package/.next/server/pages/_error.js.nft.json +1 -1
- package/.next/server/pages/api/fs/auth/login.js +1 -0
- package/.next/server/pages/api/fs/auth/login.js.nft.json +1 -0
- package/.next/server/pages/api/fs/logout.js.nft.json +1 -1
- package/.next/server/pages/api/graphql.js.nft.json +1 -1
- package/.next/server/pages/api/health/live.js.nft.json +1 -1
- package/.next/server/pages/api/health/ready.js.nft.json +1 -1
- package/.next/server/pages/api/preview.js.nft.json +1 -1
- package/.next/server/pages/checkout.js +1 -1
- package/.next/server/pages/checkout.js.nft.json +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/fs-auth-login.html +42 -0
- package/.next/server/pages/en-US/login.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/fs-auth-login.js.nft.json +1 -0
- package/.next/server/pages/index.js +1 -1
- package/.next/server/pages/index.js.nft.json +1 -1
- package/.next/server/pages/login.js +1 -1
- package/.next/server/pages/login.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/403.js +1 -1
- package/.next/server/pages/pvt/account/403.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/404.js +1 -1
- package/.next/server/pages/pvt/account/404.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/[...unknown].js.nft.json +1 -1
- package/.next/server/pages/pvt/account/orders/[id].js +1 -1
- package/.next/server/pages/pvt/account/orders/[id].js.nft.json +1 -1
- package/.next/server/pages/pvt/account/orders.js +1 -1
- package/.next/server/pages/pvt/account/orders.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/profile.js +1 -1
- package/.next/server/pages/pvt/account/profile.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/security.js +1 -1
- package/.next/server/pages/pvt/account/security.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/user-details.js +1 -1
- package/.next/server/pages/pvt/account/user-details.js.nft.json +1 -1
- package/.next/server/pages/pvt/account.js.nft.json +1 -1
- package/.next/server/pages/s.js +1 -1
- package/.next/server/pages/s.js.nft.json +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/server/src/middleware.js +5417 -0
- package/.next/server/src/middleware.js.map +1 -0
- package/.next/server/webpack-runtime.js +1 -1
- package/.next/static/9kMY_8ze-x7sawSXOfQGe/_buildManifest.js +1 -0
- package/.next/static/chunks/{2927.5a79877943a6bf7c.js → 2927.23bae2c79f0ac0f3.js} +1 -1
- package/.next/static/chunks/{UIToast.19a8664c01a00d3a.js → UIToast.de15325248043ce5.js} +1 -1
- package/.next/static/chunks/main-083a618181bb5fbb.js +1 -0
- package/.next/static/chunks/pages/fs-auth-login-ba2d1b3ef0ef0415.js +1 -0
- package/.next/static/chunks/webpack-ff85816fb58111fa.js +1 -0
- package/.next/static/css/3bd4edd425711792.css +1 -0
- package/.next/trace +156 -143
- package/.turbo/turbo-build.log +44 -19
- package/.turbo/turbo-test.log +11 -10
- package/CHANGELOG.md +6 -0
- package/package.json +3 -2
- package/src/middleware.ts +87 -0
- package/src/pages/api/fs/auth/login.ts +123 -0
- package/src/pages/fs-auth-login/fs-auth-login.module.scss +41 -0
- package/src/pages/fs-auth-login/index.tsx +90 -0
- package/src/server/authentication-service.ts +270 -0
- package/src/server/password-protection/webops-api.ts +38 -0
- package/src/utils/loginResponse.ts +20 -0
- package/test/server/authentication-service.test.ts +460 -0
- package/.next/static/UmIFhJcdMOfy3xrHNNZS2/_buildManifest.js +0 -1
- package/.next/static/chunks/main-ec03882c4375091d.js +0 -1
- package/.next/static/chunks/webpack-65b1de5f075b8367.js +0 -1
- package/src/middleware__DISABLED.ts +0 -65
- /package/.next/static/{UmIFhJcdMOfy3xrHNNZS2 → 9kMY_8ze-x7sawSXOfQGe}/_ssgManifest.js +0 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.99.
|
|
2
|
+
> @faststore/core@3.99.6 prebuild /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> na run partytown && na run generate
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @faststore/core@3.99.
|
|
6
|
+
> @faststore/core@3.99.6 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.99.
|
|
11
|
+
> @faststore/core@3.99.6 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.99.
|
|
15
|
+
> @faststore/core@3.99.6 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.99.
|
|
20
|
+
> @faststore/core@3.99.6 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.99.
|
|
40
|
+
> @faststore/core@3.99.6 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.99.
|
|
44
|
+
> @faststore/core@3.99.6 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
|
|
@@ -58,7 +58,7 @@ Browserslist: caniuse-lite is outdated. Please run:
|
|
|
58
58
|
Creating an optimized production build ...
|
|
59
59
|
Disabled SWC as replacement for Babel because of custom Babel configuration ".babelrc.js" https://nextjs.org/docs/messages/swc-disabled
|
|
60
60
|
Using external babel configuration from /home/runner/work/faststore/faststore/packages/core/.babelrc.js
|
|
61
|
-
Browserslist: browsers data (caniuse-lite) is
|
|
61
|
+
Browserslist: browsers data (caniuse-lite) is 17 months old. Please run:
|
|
62
62
|
npx update-browserslist-db@latest
|
|
63
63
|
Why you should do it regularly: https://github.com/browserslist/update-db#readme
|
|
64
64
|
<w> [webpack.cache.PackFileCacheStrategy] Skipped not serializable cache item 'Compilation/modules|/home/runner/work/faststore/faststore/node_modules/.pnpm/next@13.5.11_@babel+core@7.26.7_@opentelemetry+api@1.4.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.83.4/node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[7].oneOf[9].use[1]!/home/runner/work/faststore/faststore/node_modules/.pnpm/next@13.5.11_@babel+core@7.26.7_@opentelemetry+api@1.4.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.83.4/node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[7].oneOf[9].use[2]!/home/runner/work/faststore/faststore/node_modules/.pnpm/next@13.5.11_@babel+core@7.26.7_@opentelemetry+api@1.4.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.83.4/node_modules/next/dist/build/webpack/loaders/resolve-url-loader/index.js??ruleSet[1].rules[7].oneOf[9].use[3]!/home/runner/work/faststore/faststore/node_modules/.pnpm/next@13.5.11_@babel+core@7.26.7_@opentelemetry+api@1.4.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.83.4/node_modules/next/dist/compiled/sass-loader/cjs.js??ruleSet[1].rules[7].oneOf[9].use[4]!/home/runner/work/faststore/faststore/packages/core/src/components/common/Toast/section.module.scss': No serializer registered for Warning
|
|
@@ -77,19 +77,39 @@ Import trace for requested module:
|
|
|
77
77
|
./src/components/common/Toast/index.ts
|
|
78
78
|
./src/components/cms/RenderSections.tsx
|
|
79
79
|
|
|
80
|
+
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/lib/deflate.js
|
|
81
|
+
A Node.js API is used (CompressionStream at line: 10) which is not supported in the Edge Runtime.
|
|
82
|
+
Learn more: https://nextjs.org/docs/api-reference/edge-runtime
|
|
83
|
+
|
|
84
|
+
Import trace for requested module:
|
|
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/decrypt.js
|
|
87
|
+
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/index.js
|
|
88
|
+
./src/server/authentication-service.ts
|
|
89
|
+
|
|
90
|
+
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/lib/deflate.js
|
|
91
|
+
A Node.js API is used (DecompressionStream at line: 25) which is not supported in the Edge Runtime.
|
|
92
|
+
Learn more: https://nextjs.org/docs/api-reference/edge-runtime
|
|
93
|
+
|
|
94
|
+
Import trace for requested module:
|
|
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/decrypt.js
|
|
97
|
+
../../node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/index.js
|
|
98
|
+
./src/server/authentication-service.ts
|
|
99
|
+
|
|
80
100
|
Collecting page data ...
|
|
81
|
-
Generating static pages (0/
|
|
101
|
+
Generating static pages (0/8) ...
|
|
102
|
+
|
|
82
103
|
Generating static pages (2/8)
|
|
83
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.
|
|
84
106
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
107
|
+
|
|
85
108
|
Generating static pages (4/8)
|
|
86
109
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
87
|
-
|
|
88
110
|
Generating static pages (1/6)
|
|
89
|
-
|
|
90
111
|
Generating static pages (2/6)
|
|
91
|
-
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.
|
|
92
112
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
113
|
+
|
|
93
114
|
Generating static pages (6/8)
|
|
94
115
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
95
|
-
|
|
96
116
|
Generating static pages (4/6)
|
|
97
117
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
98
|
-
|
|
99
118
|
✓ Generating static pages (6/6)
|
|
119
|
+
|
|
100
120
|
✓ Generating static pages (8/8)
|
|
101
121
|
Finalizing page optimization ...
|
|
102
122
|
Collecting build traces ...
|
|
103
123
|
|
|
@@ -101,14 +121,17 @@ Route (pages) Size First Load JS
|
|
|
101
121
|
├ ● /[slug]/p 97.3 kB 255 kB
|
|
102
122
|
├ ├ css/1c4983f11b861ea0.css 6.34 kB
|
|
103
123
|
├ └ css/54cedf4b65e5863f.css 16.7 kB
|
|
104
|
-
├ ○ /404 1.58 kB
|
|
105
|
-
├ ● /500 1.58 kB
|
|
124
|
+
├ ○ /404 1.58 kB 160 kB
|
|
125
|
+
├ ● /500 1.58 kB 160 kB
|
|
126
|
+
├ λ /api/fs/auth/login 0 B 109 kB
|
|
106
127
|
├ λ /api/fs/logout 0 B 109 kB
|
|
107
128
|
├ λ /api/graphql 0 B 109 kB
|
|
108
129
|
├ λ /api/health/live 0 B 109 kB
|
|
109
130
|
├ λ /api/health/ready 0 B 109 kB
|
|
110
131
|
├ λ /api/preview 0 B 109 kB
|
|
111
132
|
├ ● /checkout 750 B 159 kB
|
|
133
|
+
├ ○ /fs-auth-login 2.17 kB 111 kB
|
|
134
|
+
├ └ css/3bd4edd425711792.css 3.2 kB
|
|
112
135
|
├ ● /login 1.7 kB 160 kB
|
|
113
136
|
├ λ /pvt/account 247 B 109 kB
|
|
114
137
|
├ ● /pvt/account/[...unknown] 287 B 109 kB
|
|
@@ -118,7 +141,7 @@ Route (pages) Size First Load JS
|
|
|
118
141
|
├ └ css/ea11d74a2848b093.css 4.89 kB
|
|
119
142
|
├ λ /pvt/account/orders 9.89 kB 168 kB
|
|
120
143
|
├ └ css/14176a4704ff97b2.css 14.4 kB
|
|
121
|
-
├ λ /pvt/account/orders/[id] 13.6 kB
|
|
144
|
+
├ λ /pvt/account/orders/[id] 13.6 kB 172 kB
|
|
122
145
|
├ └ css/82f3cd529b672812.css 14 kB
|
|
123
146
|
├ λ /pvt/account/profile 1.99 kB 160 kB
|
|
124
147
|
├ └ css/a852afa9be31e946.css 4.58 kB
|
|
@@ -129,11 +152,13 @@ Route (pages) Size First Load JS
|
|
|
129
152
|
└ ● /s 3.35 kB 176 kB
|
|
130
153
|
+ First Load JS shared by all 118 kB
|
|
131
154
|
├ chunks/framework-d514426edf885c68.js 45.4 kB
|
|
132
|
-
├ chunks/main-
|
|
155
|
+
├ chunks/main-083a618181bb5fbb.js 33.4 kB
|
|
133
156
|
├ chunks/pages/_app-35e8dda638ee2672.js 26.6 kB
|
|
134
|
-
├ chunks/webpack-
|
|
157
|
+
├ chunks/webpack-ff85816fb58111fa.js 3.9 kB
|
|
135
158
|
└ css/146a8678babc61bf.css 9.2 kB
|
|
136
159
|
|
|
160
|
+
ƒ Middleware 44.8 kB
|
|
161
|
+
|
|
137
162
|
λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
|
|
138
163
|
○ (Static) automatically rendered as static HTML (uses no initial props)
|
|
139
164
|
● (SSG) automatically generated as static HTML + JSON (uses getStaticProps)
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.99.
|
|
2
|
+
> @faststore/core@3.99.6 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> jest
|
|
4
4
|
|
|
5
|
-
PASS test/utils/
|
|
6
|
-
PASS test/utils/
|
|
7
|
-
PASS test/utils/cookieCacheBusting.test.ts (
|
|
8
|
-
PASS test/server/
|
|
5
|
+
PASS test/utils/clearCookies.test.ts (11.099 s)
|
|
6
|
+
PASS test/utils/multipleTemplates.test.ts
|
|
7
|
+
PASS test/utils/cookieCacheBusting.test.ts (14.855 s)
|
|
8
|
+
PASS test/server/authentication-service.test.ts (16.605 s)
|
|
9
9
|
PASS test/utils/validateSessionRefreshToken.test.ts
|
|
10
|
+
PASS test/server/cms/global.test.ts
|
|
10
11
|
PASS test/utils/isLocalHost.test.ts
|
|
12
|
+
PASS test/server/cms/index.test.ts
|
|
11
13
|
PASS test/utils/isLocalHost.browser.test.ts
|
|
12
|
-
PASS test/server/
|
|
13
|
-
PASS test/server/index.test.ts (13.099 s)
|
|
14
|
+
PASS test/server/index.test.ts (10.697 s)
|
|
14
15
|
|
|
15
|
-
Test Suites:
|
|
16
|
-
Tests:
|
|
16
|
+
Test Suites: 10 passed, 10 total
|
|
17
|
+
Tests: 85 passed, 85 total
|
|
17
18
|
Snapshots: 0 total
|
|
18
|
-
Time:
|
|
19
|
+
Time: 27.703 s
|
|
19
20
|
Ran all test suites.
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
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.0](https://github.com/vtex/faststore/compare/v3.99.6...v3.100.0) (2026-06-02)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- Password Protection (v3) ([#3347](https://github.com/vtex/faststore/issues/3347)) ([e215c72](https://github.com/vtex/faststore/commit/e215c72af5bf49783790a8d5ea7316d7c415ec57))
|
|
11
|
+
|
|
6
12
|
## [3.99.6](https://github.com/vtex/faststore/compare/v3.99.5...v3.99.6) (2026-05-19)
|
|
7
13
|
|
|
8
14
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.100.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"idb-keyval": "^5.1.3",
|
|
89
89
|
"include-media": "^1.4.10",
|
|
90
90
|
"isomorphic-unfetch": "^3.1.0",
|
|
91
|
+
"jose": "^6.2.3",
|
|
91
92
|
"lexical": "^0.34.0",
|
|
92
93
|
"next": "^13.5.9",
|
|
93
94
|
"next-logger": "^5.0.2",
|
|
@@ -126,5 +127,5 @@
|
|
|
126
127
|
"ts-jest": "29.1.1",
|
|
127
128
|
"typescript": "5.3.2"
|
|
128
129
|
},
|
|
129
|
-
"gitHead": "
|
|
130
|
+
"gitHead": "0270a50a08d76544dd1c442635265785b12f793e"
|
|
130
131
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Middleware is always active. It runs:
|
|
3
|
+
* 1. Password protection (AuthenticationService) — when applicable (default/custom domains per env).
|
|
4
|
+
* 2. Redirects — only when ENABLE_REDIRECTS_MIDDLEWARE is set at runtime.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { NextResponse } from 'next/server'
|
|
8
|
+
import type { NextRequest } from 'next/server'
|
|
9
|
+
import storeConfig from 'discovery.config'
|
|
10
|
+
|
|
11
|
+
import { AuthenticationService } from './server/authentication-service'
|
|
12
|
+
|
|
13
|
+
type Redirect = {
|
|
14
|
+
from: string
|
|
15
|
+
to: string
|
|
16
|
+
type: 'permanent' | 'temporary'
|
|
17
|
+
}
|
|
18
|
+
interface RedirectsClient {
|
|
19
|
+
get(from: string): Promise<Redirect | null>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class DynamoRedirectsClient implements RedirectsClient {
|
|
23
|
+
async get(_from: string): Promise<Redirect | null> {
|
|
24
|
+
// TODO: Implement DynamoDB client. Ensure that the cluster has access to DynamoDB first.
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const redirectsClient = new DynamoRedirectsClient()
|
|
30
|
+
|
|
31
|
+
export async function middleware(request: NextRequest) {
|
|
32
|
+
const path = request.nextUrl.pathname
|
|
33
|
+
|
|
34
|
+
let authResult: Awaited<
|
|
35
|
+
ReturnType<AuthenticationService['authenticateRequest']>
|
|
36
|
+
>
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const authService = new AuthenticationService()
|
|
40
|
+
authResult = await authService.authenticateRequest(request)
|
|
41
|
+
} catch {
|
|
42
|
+
return NextResponse.error()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (authResult.response.status !== 200) {
|
|
46
|
+
return authResult.response
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (process.env.ENABLE_REDIRECTS_MIDDLEWARE === 'true') {
|
|
50
|
+
const redirect = await redirectsClient.get(path)
|
|
51
|
+
|
|
52
|
+
if (redirect) {
|
|
53
|
+
const redirectUrl = new URL(redirect.to, storeConfig.storeUrl)
|
|
54
|
+
const redirectStatusCode = redirect.type === 'permanent' ? 301 : 302
|
|
55
|
+
const response = NextResponse.redirect(redirectUrl, redirectStatusCode)
|
|
56
|
+
|
|
57
|
+
for (const cookie of authResult.response.cookies.getAll()) {
|
|
58
|
+
response.cookies.set(cookie)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
response.headers.set(
|
|
62
|
+
'Cache-Control',
|
|
63
|
+
'public, max-age=300, stale-while-revalidate=31536000'
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
return response
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return authResult.response
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const config = {
|
|
74
|
+
matcher: [
|
|
75
|
+
/*
|
|
76
|
+
* Match all paths including `/`
|
|
77
|
+
* Exclude:
|
|
78
|
+
* - api (e.g. api/fs/auth/login)
|
|
79
|
+
* - _next/static, _next/image
|
|
80
|
+
* - favicon.ico
|
|
81
|
+
* - fs-auth-login (login page)
|
|
82
|
+
* - ~partytown (partytown scripts)
|
|
83
|
+
*/
|
|
84
|
+
'/',
|
|
85
|
+
'/((?!api|_next/static|_next/image|favicon.ico|fs-auth-login|~partytown).*)',
|
|
86
|
+
],
|
|
87
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
|
|
2
|
+
|
|
3
|
+
import storeConfig from 'discovery.config'
|
|
4
|
+
|
|
5
|
+
import type { LoginResponse } from '../../../../utils/loginResponse'
|
|
6
|
+
import {
|
|
7
|
+
sessionUrl,
|
|
8
|
+
passwordProtectionTimeouts,
|
|
9
|
+
} from '../../../../server/password-protection/webops-api'
|
|
10
|
+
import {
|
|
11
|
+
COOKIE_NAME,
|
|
12
|
+
TOKEN_TTL_SECONDS,
|
|
13
|
+
} from 'src/server/authentication-service'
|
|
14
|
+
|
|
15
|
+
interface WebOpsSessionPayload {
|
|
16
|
+
valid: boolean
|
|
17
|
+
token?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const isSafeReturnToPath = (value: string): boolean => {
|
|
21
|
+
return value.startsWith('/') && !value.startsWith('//')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const isWebOpsSessionPayload = (
|
|
25
|
+
data: unknown
|
|
26
|
+
): data is WebOpsSessionPayload => {
|
|
27
|
+
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const payload = data as Record<string, unknown>
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
typeof payload.valid === 'boolean' &&
|
|
35
|
+
(payload.token === undefined || typeof payload.token === 'string')
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const handler: NextApiHandler<LoginResponse> = async (
|
|
40
|
+
request: NextApiRequest,
|
|
41
|
+
response: NextApiResponse<LoginResponse>
|
|
42
|
+
) => {
|
|
43
|
+
if (request.method !== 'POST') {
|
|
44
|
+
response.status(405).end()
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const storeId = storeConfig.api.storeId
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const { password } = request.body ?? {}
|
|
52
|
+
|
|
53
|
+
if (!password || typeof password !== 'string') {
|
|
54
|
+
response.status(400).json({
|
|
55
|
+
success: false,
|
|
56
|
+
error: 'Password is required',
|
|
57
|
+
})
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const webopsResponse = await fetch(sessionUrl(), {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: { 'Content-Type': 'application/json' },
|
|
64
|
+
body: JSON.stringify({ storeId, password }),
|
|
65
|
+
signal: AbortSignal.timeout(passwordProtectionTimeouts.defaultMs),
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
if (!webopsResponse.ok) {
|
|
69
|
+
if (webopsResponse.status === 401 || webopsResponse.status === 403) {
|
|
70
|
+
response.status(401).json({
|
|
71
|
+
success: false,
|
|
72
|
+
error: 'Invalid password',
|
|
73
|
+
})
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
response.status(503).json({
|
|
78
|
+
success: false,
|
|
79
|
+
error: 'Service temporarily unavailable',
|
|
80
|
+
})
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const data: unknown = await webopsResponse.json()
|
|
85
|
+
|
|
86
|
+
if (!isWebOpsSessionPayload(data)) {
|
|
87
|
+
response.status(500).json({
|
|
88
|
+
success: false,
|
|
89
|
+
error: 'Internal server error',
|
|
90
|
+
})
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (data.valid && data.token) {
|
|
95
|
+
const returnTo =
|
|
96
|
+
typeof request.query.returnTo === 'string'
|
|
97
|
+
? request.query.returnTo
|
|
98
|
+
: '/'
|
|
99
|
+
const sanitizedReturnTo = isSafeReturnToPath(returnTo) ? returnTo : '/'
|
|
100
|
+
|
|
101
|
+
response.setHeader('Set-Cookie', [
|
|
102
|
+
`${COOKIE_NAME}=${data.token}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=${TOKEN_TTL_SECONDS}`,
|
|
103
|
+
])
|
|
104
|
+
|
|
105
|
+
response.status(200).json({
|
|
106
|
+
success: true,
|
|
107
|
+
redirectUrl: sanitizedReturnTo,
|
|
108
|
+
})
|
|
109
|
+
} else {
|
|
110
|
+
response.status(401).json({
|
|
111
|
+
success: false,
|
|
112
|
+
error: 'Invalid password',
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
response.status(503).json({
|
|
117
|
+
success: false,
|
|
118
|
+
error: 'Service temporarily unavailable',
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export default handler
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.fsAuthLogin {
|
|
3
|
+
@import "@faststore/ui/src/components/atoms/Button/styles.scss";
|
|
4
|
+
@import "@faststore/ui/src/components/atoms/Input/styles.scss";
|
|
5
|
+
@import "@faststore/ui/src/components/atoms/Loader/styles.scss";
|
|
6
|
+
@import "@faststore/ui/src/components/molecules/InputField/styles.scss";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.page {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
min-height: 100vh;
|
|
16
|
+
padding: var(--fs-spacing-3);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.title {
|
|
20
|
+
margin: 0 0 var(--fs-spacing-6) 0;
|
|
21
|
+
font-size: var(--fs-text-size-title-section);
|
|
22
|
+
font-weight: var(--fs-text-weight-bold);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.subtitle {
|
|
26
|
+
margin: 0 0 var(--fs-spacing-3) 0;
|
|
27
|
+
font-size: var(--fs-text-size-body);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.form {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
gap: var(--fs-spacing-2);
|
|
34
|
+
align-items: stretch;
|
|
35
|
+
width: 100%;
|
|
36
|
+
max-width: 20rem;
|
|
37
|
+
|
|
38
|
+
button {
|
|
39
|
+
align-self: center;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Button, InputField } from '@faststore/ui'
|
|
2
|
+
import Head from 'next/head'
|
|
3
|
+
import { useRouter } from 'next/router'
|
|
4
|
+
import { type FormEvent, useState } from 'react'
|
|
5
|
+
|
|
6
|
+
import { isLoginResponse } from '../../utils/loginResponse'
|
|
7
|
+
import styles from './fs-auth-login.module.scss'
|
|
8
|
+
|
|
9
|
+
export default function PasswordProtectionLogin() {
|
|
10
|
+
const router = useRouter()
|
|
11
|
+
const returnTo =
|
|
12
|
+
typeof router.query.returnTo === 'string' ? router.query.returnTo : '/'
|
|
13
|
+
|
|
14
|
+
const [password, setPassword] = useState('')
|
|
15
|
+
const [error, setError] = useState('')
|
|
16
|
+
const [loading, setLoading] = useState(false)
|
|
17
|
+
|
|
18
|
+
const handleSubmit = async (e: FormEvent) => {
|
|
19
|
+
e.preventDefault()
|
|
20
|
+
setLoading(true)
|
|
21
|
+
setError('')
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const url = new URL('/api/fs/auth/login', globalThis.location.origin)
|
|
25
|
+
url.searchParams.set('returnTo', returnTo)
|
|
26
|
+
|
|
27
|
+
const response = await fetch(url.toString(), {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: { 'Content-Type': 'application/json' },
|
|
30
|
+
body: JSON.stringify({ password }),
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const data: unknown = await response.json()
|
|
34
|
+
|
|
35
|
+
if (!isLoginResponse(data)) {
|
|
36
|
+
setError('Service temporarily unavailable')
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (data.success && data.redirectUrl) {
|
|
41
|
+
globalThis.location.href = data.redirectUrl
|
|
42
|
+
} else {
|
|
43
|
+
setError(data.error ?? 'Invalid password')
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
setError('Service temporarily unavailable')
|
|
47
|
+
} finally {
|
|
48
|
+
setLoading(false)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className={styles.fsAuthLogin}>
|
|
54
|
+
<Head>
|
|
55
|
+
<meta name="robots" content="noindex,nofollow" />
|
|
56
|
+
</Head>
|
|
57
|
+
<div className={styles.page}>
|
|
58
|
+
<h1 className={styles.title}>This store is password protected</h1>
|
|
59
|
+
|
|
60
|
+
<h2 className={styles.subtitle}>
|
|
61
|
+
Enter the password to access the store
|
|
62
|
+
</h2>
|
|
63
|
+
|
|
64
|
+
<form className={styles.form} onSubmit={handleSubmit}>
|
|
65
|
+
<InputField
|
|
66
|
+
id="fs-auth-password"
|
|
67
|
+
label="Password"
|
|
68
|
+
type="password"
|
|
69
|
+
value={password}
|
|
70
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
71
|
+
placeholder="Enter password"
|
|
72
|
+
autoComplete="current-password"
|
|
73
|
+
required
|
|
74
|
+
disabled={loading}
|
|
75
|
+
error={error || undefined}
|
|
76
|
+
/>
|
|
77
|
+
<Button
|
|
78
|
+
type="submit"
|
|
79
|
+
variant="primary"
|
|
80
|
+
size="small"
|
|
81
|
+
disabled={loading}
|
|
82
|
+
loading={loading}
|
|
83
|
+
>
|
|
84
|
+
Login
|
|
85
|
+
</Button>
|
|
86
|
+
</form>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
}
|