@wbce-d9/api 12.5.7 → 12.5.9

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.
@@ -295,6 +295,11 @@ AUTH_PROVIDERS=""
295
295
  # AUTH_GITHUB_EMAIL_KEY="email"
296
296
  # AUTH_GITHUB_IDENTIFIER_KEY="login"
297
297
 
298
+ # Public self-service registration on the default email/password provider. Needs working EMAIL_*
299
+ # AUTH_DEFAULT_ALLOW_PUBLIC_REGISTRATION=true
300
+ # AUTH_DEFAULT_DEFAULT_ROLE_ID="82424427-c9d4-4289-8bc5-ed1bf8422c90"
301
+ # AUTH_DEFAULT_REGISTER_URL_ALLOW_LIST="https://example.com/verify-email"
302
+
298
303
  ####################################################################################################
299
304
  ### Extensions
300
305
 
@@ -1,6 +1,7 @@
1
1
  import { parseJSON } from '@wbce-d9/utils';
2
2
  import contentDisposition from 'content-disposition';
3
3
  import { Router } from 'express';
4
+ import helmet from 'helmet';
4
5
  import { merge, pick } from 'lodash-es';
5
6
  import { ASSET_TRANSFORM_QUERY_KEYS, SYSTEM_ASSET_ALLOW_LIST } from '../constants.js';
6
7
  import getDatabase from '../database/index.js';
@@ -89,14 +90,6 @@ asyncHandler(async (req, res, next) => {
89
90
  return next();
90
91
  throw new InvalidQueryException(`Dynamic asset generation has been disabled for this project.`);
91
92
  }
92
- }), asyncHandler(async (req, res, next) => {
93
- const helmet = await import('helmet');
94
- return helmet.contentSecurityPolicy(merge({
95
- useDefaults: false,
96
- directives: {
97
- defaultSrc: ['none'],
98
- },
99
- }, getConfigFromEnv('ASSETS_CONTENT_SECURITY_POLICY')))(req, res, next);
100
93
  }),
101
94
  // Return file
102
95
  asyncHandler(async (req, res) => {
@@ -144,7 +137,21 @@ asyncHandler(async (req, res) => {
144
137
  const filename = req.params['filename'] ?? file.filename_download;
145
138
  res.attachment(filename);
146
139
  res.setHeader('Content-Type', file.type);
140
+ res.setHeader('X-Content-Type-Options', 'nosniff');
147
141
  res.setHeader('Accept-Ranges', 'bytes');
142
+ helmet.contentSecurityPolicy(merge({
143
+ useDefaults: false,
144
+ directives: {
145
+ defaultSrc: ["'none'"],
146
+ // form-action doesn't fall back to default-src
147
+ formAction: ["'none'"],
148
+ // Serve assets from an opaque origin, except PDFs which browsers refuse to render when sandboxed
149
+ ...(file.type !== 'application/pdf' ? { sandbox: [] } : {}),
150
+ },
151
+ }, getConfigFromEnv('ASSETS_CONTENT_SECURITY_POLICY')))(req, res, (err) => {
152
+ if (err)
153
+ throw err;
154
+ });
148
155
  res.setHeader('Cache-Control', getCacheControlHeader(req, getMilliseconds(env['ASSETS_CACHE_TTL']), false, true));
149
156
  res.setHeader('Vary', vary.join(', '));
150
157
  const unixTime = Date.parse(file.modified_on);
@@ -75,9 +75,14 @@ export class FilesService extends ItemsService {
75
75
  const { height, width, description, title, tags, metadata } = await this.getMetadata(stream);
76
76
  payload.height ??= height ?? null;
77
77
  payload.width ??= width ?? null;
78
- payload.description ??= description ?? null;
79
- payload.title ??= title ?? null;
80
- payload.tags ??= tags ?? null;
78
+ // Only fill these from metadata the file actually carries. Setting them to null would wipe the stored values
79
+ // when a file is replaced with one that has none, e.g. a screenshot.
80
+ if (description)
81
+ payload.description ??= description;
82
+ if (title)
83
+ payload.title ??= title;
84
+ if (tags)
85
+ payload.tags ??= tags;
81
86
  payload.metadata ??= metadata ?? null;
82
87
  }
83
88
  // We do this in a service without accountability. Even if you don't have update permissions to the file,
@@ -5,9 +5,17 @@ import { version } from './package.js';
5
5
  export function getCacheKey(req) {
6
6
  const path = url.parse(req.originalUrl).pathname;
7
7
  const isGraphQl = path?.startsWith('/graphql');
8
+ const accountability = req.accountability;
9
+ // Include every accountability field that affects permission resolution (see get-permissions.ts),
10
+ // so responses are never shared across roles, shares or share scopes
8
11
  const info = {
9
12
  version,
10
- user: req.accountability?.user || null,
13
+ user: accountability?.user || null,
14
+ role: accountability?.role || null,
15
+ admin: accountability?.admin || false,
16
+ app: accountability?.app || false,
17
+ share: accountability?.share || null,
18
+ share_scope: accountability?.share_scope || null,
11
19
  path,
12
20
  query: isGraphQl ? getGraphqlQueryAndVariables(req) : req.sanitizedQuery,
13
21
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wbce-d9/api",
3
- "version": "12.5.7",
3
+ "version": "12.5.9",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -144,18 +144,18 @@
144
144
  "tsx": "3.12.6",
145
145
  "uuid-validate": "0.0.3",
146
146
  "@wbce-d9/app": "11.0.0",
147
- "@wbce-d9/constants": "10.0.0",
148
- "@wbce-d9/extensions-sdk": "10.0.4",
149
147
  "@wbce-d9/exceptions": "10.0.0",
150
- "@wbce-d9/schema": "10.0.0",
151
148
  "@wbce-d9/specs": "9.26.5",
152
- "@wbce-d9/storage-driver-azure": "10.0.3",
149
+ "@wbce-d9/schema": "10.0.0",
150
+ "@wbce-d9/extensions-sdk": "10.0.4",
153
151
  "@wbce-d9/storage": "10.0.0",
154
- "@wbce-d9/storage-driver-cloudinary": "10.0.4",
155
- "@wbce-d9/storage-driver-gcs": "10.0.3",
152
+ "@wbce-d9/constants": "10.0.0",
156
153
  "@wbce-d9/storage-driver-s3": "10.0.3",
154
+ "@wbce-d9/storage-driver-azure": "10.0.3",
157
155
  "@wbce-d9/update-check": "10.0.4",
158
156
  "@wbce-d9/utils": "10.0.3",
157
+ "@wbce-d9/storage-driver-gcs": "10.0.3",
158
+ "@wbce-d9/storage-driver-cloudinary": "10.0.4",
159
159
  "@wbce-d9/storage-driver-local": "10.0.3"
160
160
  },
161
161
  "devDependencies": {