Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: nuxt security #916

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
},
"dependencies": {
"@types/cors": "^2.8.17",
"@vue-storefront/middleware": "3.10.0",
"@vue-storefront/middleware": "3.10.1",
"consola": "^3.2.3",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"dotenv": "^16.4.7",
"express": "^4.21.2"
},
"devDependencies": {
"@types/express": "^5.0.0",
"eslint": "^8.57.0",
"eslint-plugin-prettier": "5.1.3",
"nodemon": "^3.1.4",
"eslint": "^8.57.1",
"eslint-plugin-prettier": "5.2.1",
"nodemon": "^3.1.9",
"ts-node-dev": "^2.0.0",
"tsup": "^7.2.0"
}
Expand Down
40 changes: 20 additions & 20 deletions apps/web/assets/_variables.scss
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
$color-2-primary-50: 222 247 252;
$color-2-primary-100: 189 238 250;
$color-2-primary-200: 123 222 244;
$color-2-primary-300: 62 207 239;
$color-2-primary-400: 17 176 212;
$color-2-primary-500: 12 121 146;
$color-2-primary-600: 10 98 118;
$color-2-primary-700: 7 74 90;
$color-2-primary-800: 5 47 57;
$color-2-primary-900: 2 24 28;
$color-2-primary-50: 222 247 252 !default;
$color-2-primary-100: 189 238 250 !default;
$color-2-primary-200: 123 222 244 !default;
$color-2-primary-300: 62 207 239 !default;
$color-2-primary-400: 17 176 212 !default;
$color-2-primary-500: 12 121 146 !default;
$color-2-primary-600: 10 98 118 !default;
$color-2-primary-700: 7 74 90 !default;
$color-2-primary-800: 5 47 57 !default;
$color-2-primary-900: 2 24 28 !default;

$color-2-secondary-50: 224 247 255;
$color-2-secondary-100: 189 238 255;
$color-2-secondary-200: 128 223 255;
$color-2-secondary-300: 61 207 255;
$color-2-secondary-400: 0 191 255;
$color-2-secondary-500: 0 142 189;
$color-2-secondary-600: 0 115 153;
$color-2-secondary-700: 0 84 112;
$color-2-secondary-800: 0 57 77;
$color-2-secondary-900: 0 27 36;
$color-2-secondary-50: 224 247 255 !default;
$color-2-secondary-100: 189 238 255 !default;
$color-2-secondary-200: 128 223 255 !default;
$color-2-secondary-300: 61 207 255 !default;
$color-2-secondary-400: 0 191 255 !default;
$color-2-secondary-500: 0 142 189 !default;
$color-2-secondary-600: 0 115 153 !default;
$color-2-secondary-700: 0 84 112 !default;
$color-2-secondary-800: 0 57 77 !default;
$color-2-secondary-900: 0 27 36 !default;
43 changes: 21 additions & 22 deletions apps/web/assets/style.scss
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
@import '_variables';
@use '_variables' as vars;

:root {
--colors-2-primary-50: #{$color-2-primary-50};
--colors-2-primary-100: #{$color-2-primary-100};
--colors-2-primary-200: #{$color-2-primary-200};
--colors-2-primary-300: #{$color-2-primary-300};
--colors-2-primary-400: #{$color-2-primary-400};
--colors-2-primary-500: #{$color-2-primary-500};
--colors-2-primary-600: #{$color-2-primary-600};
--colors-2-primary-700: #{$color-2-primary-700};
--colors-2-primary-800: #{$color-2-primary-800};
--colors-2-primary-900: #{$color-2-primary-900};
--colors-2-primary-50: #{vars.$color-2-primary-50};
--colors-2-primary-100: #{vars.$color-2-primary-100};
--colors-2-primary-200: #{vars.$color-2-primary-200};
--colors-2-primary-300: #{vars.$color-2-primary-300};
--colors-2-primary-400: #{vars.$color-2-primary-400};
--colors-2-primary-500: #{vars.$color-2-primary-500};
--colors-2-primary-600: #{vars.$color-2-primary-600};
--colors-2-primary-700: #{vars.$color-2-primary-700};
--colors-2-primary-800: #{vars.$color-2-primary-800};
--colors-2-primary-900: #{vars.$color-2-primary-900};

--colors-2-secondary-50: #{$color-2-secondary-50};
--colors-2-secondary-100: #{$color-2-secondary-100};
--colors-2-secondary-200: #{$color-2-secondary-200};
--colors-2-secondary-300: #{$color-2-secondary-300};
--colors-2-secondary-400: #{$color-2-secondary-400};
--colors-2-secondary-500: #{$color-2-secondary-500};
--colors-2-secondary-600: #{$color-2-secondary-600};
--colors-2-secondary-700: #{$color-2-secondary-700};
--colors-2-secondary-800: #{$color-2-secondary-800};
--colors-2-secondary-900: #{$color-2-secondary-900};
--colors-2-secondary-50: #{vars.$color-2-secondary-50};
--colors-2-secondary-100: #{vars.$color-2-secondary-100};
--colors-2-secondary-200: #{vars.$color-2-secondary-200};
--colors-2-secondary-300: #{vars.$color-2-secondary-300};
--colors-2-secondary-400: #{vars.$color-2-secondary-400};
--colors-2-secondary-500: #{vars.$color-2-secondary-500};
--colors-2-secondary-600: #{vars.$color-2-secondary-600};
--colors-2-secondary-700: #{vars.$color-2-secondary-700};
--colors-2-secondary-800: #{vars.$color-2-secondary-800};
--colors-2-secondary-900: #{vars.$color-2-secondary-900};
}

.scrollbar-hidden {
Expand Down Expand Up @@ -112,6 +112,5 @@ apple-pay-button {
svg,
video {
display: block;
vertical-align: middle;
}
}
108 changes: 108 additions & 0 deletions apps/web/configuration/security.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import {
AllowedHTTPMethods,
BasicAuth,
CorsOptions,
ContentSecurityPolicyValue,
CrossOriginEmbedderPolicyValue,
CrossOriginOpenerPolicyValue,
CrossOriginResourcePolicyValue,
HTTPMethod,
PermissionsPolicyValue,
RateLimiter,
ReferrerPolicyValue,
RequestSizeLimiter,
StrictTransportSecurityValue,
Ssg,
XDnsPrefetchControlValue,
XFrameOptionsValue,
XPermittedCrossDomainPoliciesValue,
XssValidator,
} from 'nuxt-security';

// Enabling 'unsafe-eval' and 'unsafe-inline' can create security risks
// TODO: If these are not strictly necessary, we should aim to avoid them

export const securityConfiguration = {
strict: false,
headers: {
crossOriginResourcePolicy: 'same-origin' as CrossOriginResourcePolicyValue,
crossOriginOpenerPolicy: 'same-origin' as CrossOriginOpenerPolicyValue,
crossOriginEmbedderPolicy: 'credentialless' as CrossOriginEmbedderPolicyValue,
contentSecurityPolicy: {
'base-uri': ["'none'"],
'font-src': ["'self'", 'https:', 'data:'],
'form-action': ["'self'"],
'frame-ancestors': ["'self'"],
'img-src': ["'self'", 'data:', 'https://cdn02.plentymarkets.com'],
'object-src': ["'none'"],
'script-src-attr': ["'unsafe-inline'"],
'style-src': ["'self'", 'https:', "'unsafe-inline'"],
'script-src': ["'self'", 'https:', "'unsafe-inline'", "'strict-dynamic'", "'nonce-{{nonce}}'", "'unsafe-eval'"],
'upgrade-insecure-requests': true,
'report-to': '', // Sends CSP violation reports to our server
'report-uri': '', // Legacy reporting method
} as ContentSecurityPolicyValue,
originAgentCluster: '?1' as const,
referrerPolicy: 'no-referrer' as ReferrerPolicyValue,
strictTransportSecurity: {
maxAge: 31536000, // 1 year
includeSubdomains: true,
preload: true, // We should consider adding to the HSTS preload list
} as StrictTransportSecurityValue,
xContentTypeOptions: 'nosniff' as const,
xDNSPrefetchControl: 'off' as XDnsPrefetchControlValue,
xDownloadOptions: 'noopen' as const,
xFrameOptions: 'SAMEORIGIN' as XFrameOptionsValue,
xPermittedCrossDomainPolicies: 'none' as XPermittedCrossDomainPoliciesValue,
xXSSProtection: '0',
permissionsPolicy: {
camera: [],
'display-capture': [],
fullscreen: [],
geolocation: [],
microphone: [],
} as PermissionsPolicyValue,
},
requestSizeLimiter: {
maxRequestSizeInBytes: 2_000_000,
maxUploadFileRequestInBytes: 8_000_000,
throwError: true,
} as RequestSizeLimiter,
rateLimiter: {
tokensPerInterval: 150,
interval: 300_000,
headers: false,
driver: {
name: 'lruCache',
},
throwError: true,
} as RateLimiter,
xssValidator: {
throwError: true,
} as XssValidator,
corsHandler: {
origin: 'http://localhost:3000', // Limit to specific trusted domains
methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'] as HTTPMethod[],
preflight: {
statusCode: 204,
},
} as CorsOptions,
allowedMethodsRestricter: {
methods: '*',
throwError: true,
} as AllowedHTTPMethods,
hidePoweredBy: true,
basicAuth: false as false | BasicAuth,
enabled: true,
csrf: false,
nonce: true,
removeLoggers: true,
ssg: {
meta: true,
hashScripts: true,
hashStyles: false,
nitroHeaders: true,
exportToPresets: true,
} as Ssg,
sri: true,
};
7 changes: 3 additions & 4 deletions apps/web/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import cookieConfig from './configuration/cookie.config';
import { nuxtI18nOptions } from './configuration/i18n.config';
import { appConfiguration } from './configuration/app.config';
import { fontFamilyNuxtConfig } from './configuration/fontFamily.config';
import { securityConfiguration } from './configuration/security.config';

export default defineNuxtConfig({
telemetry: false,
Expand All @@ -12,6 +13,7 @@ export default defineNuxtConfig({
typeCheck: true,
},
app: appConfiguration,
security: securityConfiguration,
experimental: {
asyncContext: true,
},
Expand All @@ -23,8 +25,6 @@ export default defineNuxtConfig({
dirs: ['composables', 'composables/**', 'utils/**'],
},
css: ['~/assets/style.scss'],
// eslint-disable-next-line unicorn/expiring-todo-comments
// TODO: build is consistently failing because of this. check whether we need pre-render check.
nitro: {
prerender: {
crawlLinks: false,
Expand Down Expand Up @@ -67,6 +67,7 @@ export default defineNuxtConfig({
},
},
modules: [
'nuxt-security',
'@nuxt/image',
'@nuxt/test-utils/module',
'@nuxtjs/google-fonts',
Expand Down Expand Up @@ -181,7 +182,6 @@ export default defineNuxtConfig({
navigationPreload: true,
runtimeCaching: [
{
// @ts-ignore
urlPattern: ({ request }) => request.mode === 'navigate',
handler: 'NetworkOnly',
options: {
Expand Down Expand Up @@ -216,7 +216,6 @@ export default defineNuxtConfig({
},
],
},

registerWebManifestInRouteRules: true,
},
});
48 changes: 24 additions & 24 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,48 +27,48 @@
"dependencies": {
"@plentymarkets/tailwind-colors": "^1.0.0",
"@vue-storefront/sdk": "^1.5.0",
"@vueuse/core": "^10.11.0",
"axios": "^1.7.2",
"@vueuse/core": "^10.11.1",
"axios": "^1.7.9",
"lodash-es": "^4.17.21",
"nuxt-lazy-hydrate": "^1.0.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@nuxt/image": "^1.7.0",
"@nuxt/test-utils": "^3.13.1",
"@nuxt/image": "^1.8.1",
"@nuxt/test-utils": "^3.15.1",
"@nuxtjs/google-fonts": "^3.2.0",
"@nuxtjs/i18n": "8.3.1",
"@nuxtjs/sitemap": "^5.2.2",
"@nuxtjs/tailwindcss": "^6.12.0",
"@nuxtjs/turnstile": "^0.8.0",
"@nuxtjs/i18n": "8.5.6",
"@nuxtjs/sitemap": "^5.3.5",
"@nuxtjs/tailwindcss": "^6.12.2",
"@nuxtjs/turnstile": "^0.9.11",
"@savvywombat/tailwindcss-grid-areas": "^3.1.0",
"@storefront-ui/typography": "^2.6.1",
"@storefront-ui/vue": "^2.6.3",
"@types/culori": "^2.1.0",
"@storefront-ui/vue": "^2.6.4",
"@types/culori": "^2.1.1",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.14.9",
"@types/node": "^20.17.10",
"@vite-pwa/nuxt": "^0.10.6",
"@vitest/coverage-v8": "^0.33.0",
"@vue-storefront/middleware": "^3.10.0",
"@vue-storefront/middleware": "^3.10.1",
"@vue-storefront/nuxt": "^3.1.1",
"@vue-storefront/unified-data-model": "^0.18.1",
"@vue/test-utils": "^2.4.6",
"cypress": "13.15.0",
"cypress": "13.17.0",
"cypress-real-events": "^1.13.0",
"cypress-wait-until": "^2.0.1",
"eslint": "^8.57.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
"happy-dom": "^15.11.7",
"msw": "^2.6.7",
"nuxt": "^3.13.2",
"sass": "^1.77.6",
"tsx": "^4.19.0",
"typedoc": "^0.26.2",
"typedoc-plugin-markdown": "^4.1.0",
"typedoc-vitepress-theme": "1.0.0",
"vitepress": "^1.2.3",
"msw": "^2.7.0",
"nuxt": "^3.14.1592",
"sass": "^1.83.0",
"tsx": "^4.19.2",
"typedoc": "^0.27.5",
"typedoc-plugin-markdown": "^4.3.3",
"typedoc-vitepress-theme": "1.1.1",
"vitepress": "^1.5.0",
"vitest": "^1.6.0",
"vue-tsc": "^2.1.6",
"vuepress": "^2.0.0-rc.14"
"vue-tsc": "^2.1.10",
"vuepress": "^2.0.0-rc.19"
}
}
12 changes: 6 additions & 6 deletions apps/web/pages/[...slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,20 @@ watch(

const headTitle = computed(() =>
productsCatalog.value?.category
? (categoryGetters.getMetaTitle(productsCatalog.value.category) || process.env.METATITLE) ?? ''
: process.env.METATITLE ?? '',
? ((categoryGetters.getMetaTitle(productsCatalog.value.category) || process.env.METATITLE) ?? '')
: (process.env.METATITLE ?? ''),
);

const descriptionContent = computed(() =>
productsCatalog.value?.category
? (categoryGetters.getMetaDescription(productsCatalog.value.category) || process.env.METADESC) ?? ''
: process.env.METADESC ?? '',
? ((categoryGetters.getMetaDescription(productsCatalog.value.category) || process.env.METADESC) ?? '')
: (process.env.METADESC ?? ''),
);

const keywordsContent = computed((): string =>
productsCatalog.value?.category
? (categoryGetters.getMetaKeywords(productsCatalog.value.category) || process.env.METAKEYWORDS) ?? ''
: process.env.METAKEYWORDS ?? '',
? ((categoryGetters.getMetaKeywords(productsCatalog.value.category) || process.env.METAKEYWORDS) ?? '')
: (process.env.METAKEYWORDS ?? ''),
);

useHead({
Expand Down
1 change: 1 addition & 0 deletions docs/changelog/changelog_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### New

- Added security module.
- Added page for shipping legal text.

### 🩹 Fixed
Expand Down
Loading
Loading