graphile-settings 6.14.0 → 6.15.1
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/esm/upload-resolver.js +16 -0
- package/package.json +20 -19
- package/upload-resolver.js +16 -0
package/esm/upload-resolver.js
CHANGED
|
@@ -29,6 +29,7 @@ import Streamer from '@constructive-io/s3-streamer';
|
|
|
29
29
|
import { Logger } from '@pgpmjs/logger';
|
|
30
30
|
import { createHash, randomUUID } from 'crypto';
|
|
31
31
|
import { finalizeStagedUpload, resolveManagedUploadTarget, withRequestPgClient, } from 'graphile-presigned-url-plugin';
|
|
32
|
+
import { checkTypeAgreement } from 'mime-bytes';
|
|
32
33
|
import { Transform } from 'stream';
|
|
33
34
|
import { createBucketNameResolver, createEnsureBucketProvisioned, getPresignedUrlS3Config, } from './presigned-url-resolver';
|
|
34
35
|
const log = new Logger('upload-resolver');
|
|
@@ -178,6 +179,21 @@ async function uploadResolver(upload, _args, context, info) {
|
|
|
178
179
|
readStream: upload.createReadStream(),
|
|
179
180
|
filename,
|
|
180
181
|
});
|
|
182
|
+
// The three claims must agree, and disagreement is rejection rather than
|
|
183
|
+
// relabelling: an `.jpg` carrying HTML is served to a browser as an image and
|
|
184
|
+
// executed as a script. Compared against `magic.type` — what the bytes say —
|
|
185
|
+
// not `contentType`, which the detector may have refined using the very
|
|
186
|
+
// extension under suspicion.
|
|
187
|
+
const agreement = checkTypeAgreement({
|
|
188
|
+
filename,
|
|
189
|
+
declaredMime: upload.mimetype,
|
|
190
|
+
detectedMime: detected.magic?.type,
|
|
191
|
+
});
|
|
192
|
+
if (!agreement.ok) {
|
|
193
|
+
detected.stream.destroy();
|
|
194
|
+
throw new Error(`UPLOAD_TYPE_MISMATCH: ${agreement.violation.message}. The upload was rejected rather than ` +
|
|
195
|
+
'stored under a type it is not.');
|
|
196
|
+
}
|
|
181
197
|
const allowed = allowedMimeTypes(tags, typ);
|
|
182
198
|
if (allowed.length && !allowed.includes(detected.contentType)) {
|
|
183
199
|
detected.stream.destroy();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphile-settings",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.15.1",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "graphile settings",
|
|
6
6
|
"main": "index.js",
|
|
@@ -31,46 +31,47 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@aws-sdk/client-s3": "^3.1052.0",
|
|
33
33
|
"@constructive-io/bucket-provisioner": "^0.24.0",
|
|
34
|
-
"@constructive-io/graphql-env": "^3.29.
|
|
35
|
-
"@constructive-io/graphql-types": "^3.28.
|
|
36
|
-
"@constructive-io/s3-streamer": "^2.40.
|
|
34
|
+
"@constructive-io/graphql-env": "^3.29.4",
|
|
35
|
+
"@constructive-io/graphql-types": "^3.28.4",
|
|
36
|
+
"@constructive-io/s3-streamer": "^2.40.2",
|
|
37
37
|
"@constructive-io/s3-utils": "^2.30.0",
|
|
38
38
|
"@constructive-io/upload-names": "^2.29.0",
|
|
39
39
|
"@dataplan/json": "1.0.1",
|
|
40
40
|
"@dataplan/pg": "1.1.1",
|
|
41
41
|
"@graphile-contrib/pg-many-to-many": "2.0.0-rc.2",
|
|
42
42
|
"@pgpmjs/logger": "^2.24.1",
|
|
43
|
-
"@pgpmjs/types": "^2.50.
|
|
43
|
+
"@pgpmjs/types": "^2.50.4",
|
|
44
44
|
"@pgsql/quotes": "^18.2.4",
|
|
45
45
|
"cors": "^2.8.6",
|
|
46
46
|
"express": "^5.2.1",
|
|
47
|
-
"grafast": "1.1.
|
|
47
|
+
"grafast": "1.1.2",
|
|
48
48
|
"grafserv": "1.0.1",
|
|
49
49
|
"graphile-bucket-provisioner-plugin": "1.12.4",
|
|
50
50
|
"graphile-build": "5.1.1",
|
|
51
51
|
"graphile-build-pg": "5.1.3",
|
|
52
|
-
"graphile-bulk-mutations": "^1.11.
|
|
52
|
+
"graphile-bulk-mutations": "^1.11.9",
|
|
53
53
|
"graphile-config": "1.1.0",
|
|
54
|
-
"graphile-connection-filter": "^2.11.
|
|
55
|
-
"graphile-history": "^1.3.
|
|
56
|
-
"graphile-i18n": "^2.11.
|
|
57
|
-
"graphile-llm": "^1.11.
|
|
58
|
-
"graphile-ltree": "^2.11.
|
|
54
|
+
"graphile-connection-filter": "^2.11.9",
|
|
55
|
+
"graphile-history": "^1.3.9",
|
|
56
|
+
"graphile-i18n": "^2.11.9",
|
|
57
|
+
"graphile-llm": "^1.11.9",
|
|
58
|
+
"graphile-ltree": "^2.11.9",
|
|
59
59
|
"graphile-meta": "^1.7.1",
|
|
60
|
-
"graphile-pg-aggregates": "^2.11.
|
|
61
|
-
"graphile-postgis": "^3.11.
|
|
62
|
-
"graphile-presigned-url-plugin": "^1.
|
|
60
|
+
"graphile-pg-aggregates": "^2.11.9",
|
|
61
|
+
"graphile-postgis": "^3.11.9",
|
|
62
|
+
"graphile-presigned-url-plugin": "^1.13.0",
|
|
63
63
|
"graphile-realtime-subscriptions": "^1.10.5",
|
|
64
|
-
"graphile-search": "^2.11.
|
|
64
|
+
"graphile-search": "^2.11.9",
|
|
65
65
|
"graphile-upload-plugin": "^2.25.0",
|
|
66
66
|
"graphile-utils": "5.0.3",
|
|
67
67
|
"graphql": "16.13.0",
|
|
68
68
|
"inflekt": "^0.8.1",
|
|
69
69
|
"lru-cache": "^11.2.7",
|
|
70
|
+
"mime-bytes": "^0.31.0",
|
|
70
71
|
"pg": "^8.21.0",
|
|
71
72
|
"pg-query-context": "^2.29.1",
|
|
72
73
|
"pg-sql2": "5.0.1",
|
|
73
|
-
"postgraphile": "5.1.
|
|
74
|
+
"postgraphile": "5.1.4",
|
|
74
75
|
"request-ip": "^3.3.0",
|
|
75
76
|
"tamedevil": "0.1.1"
|
|
76
77
|
},
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
"@types/express": "^5.0.6",
|
|
80
81
|
"@types/pg": "^8.20.4",
|
|
81
82
|
"@types/request-ip": "^0.0.41",
|
|
82
|
-
"graphile-test": "^5.11.
|
|
83
|
+
"graphile-test": "^5.11.9",
|
|
83
84
|
"makage": "^0.3.0",
|
|
84
85
|
"nodemon": "^3.1.14",
|
|
85
86
|
"ts-node": "^10.9.2"
|
|
@@ -91,5 +92,5 @@
|
|
|
91
92
|
"constructive",
|
|
92
93
|
"graphql"
|
|
93
94
|
],
|
|
94
|
-
"gitHead": "
|
|
95
|
+
"gitHead": "eacbe10ce544848c93a4c17fc8a8474d1a788a18"
|
|
95
96
|
}
|
package/upload-resolver.js
CHANGED
|
@@ -35,6 +35,7 @@ const s3_streamer_1 = __importDefault(require("@constructive-io/s3-streamer"));
|
|
|
35
35
|
const logger_1 = require("@pgpmjs/logger");
|
|
36
36
|
const crypto_1 = require("crypto");
|
|
37
37
|
const graphile_presigned_url_plugin_1 = require("graphile-presigned-url-plugin");
|
|
38
|
+
const mime_bytes_1 = require("mime-bytes");
|
|
38
39
|
const stream_1 = require("stream");
|
|
39
40
|
const presigned_url_resolver_1 = require("./presigned-url-resolver");
|
|
40
41
|
const log = new logger_1.Logger('upload-resolver');
|
|
@@ -184,6 +185,21 @@ async function uploadResolver(upload, _args, context, info) {
|
|
|
184
185
|
readStream: upload.createReadStream(),
|
|
185
186
|
filename,
|
|
186
187
|
});
|
|
188
|
+
// The three claims must agree, and disagreement is rejection rather than
|
|
189
|
+
// relabelling: an `.jpg` carrying HTML is served to a browser as an image and
|
|
190
|
+
// executed as a script. Compared against `magic.type` — what the bytes say —
|
|
191
|
+
// not `contentType`, which the detector may have refined using the very
|
|
192
|
+
// extension under suspicion.
|
|
193
|
+
const agreement = (0, mime_bytes_1.checkTypeAgreement)({
|
|
194
|
+
filename,
|
|
195
|
+
declaredMime: upload.mimetype,
|
|
196
|
+
detectedMime: detected.magic?.type,
|
|
197
|
+
});
|
|
198
|
+
if (!agreement.ok) {
|
|
199
|
+
detected.stream.destroy();
|
|
200
|
+
throw new Error(`UPLOAD_TYPE_MISMATCH: ${agreement.violation.message}. The upload was rejected rather than ` +
|
|
201
|
+
'stored under a type it is not.');
|
|
202
|
+
}
|
|
187
203
|
const allowed = allowedMimeTypes(tags, typ);
|
|
188
204
|
if (allowed.length && !allowed.includes(detected.contentType)) {
|
|
189
205
|
detected.stream.destroy();
|