@vulkano/core 1.24.0 → 1.24.2

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.
@@ -1,5 +1,67 @@
1
+ // Field names that are never exposed through populate select, whatever the
2
+ // caller asks for — a coarse, name-based backstop for common secret-shaped
3
+ // fields (defense in depth on top of the schema's own `select: false`, in
4
+ // case a referenced model forgets to mark a sensitive field itself).
5
+ const SENSITIVE_FIELD_HINTS = [
6
+ 'password', 'passwd', 'secret', 'token', 'apikey', 'api_key',
7
+ 'privatekey', 'private_key', 'hash', 'salt', 'ssn', 'creditcard',
8
+ 'credit_card', 'cvv', 'pin'
9
+ ];
10
+
11
+ function isSensitiveByName(field) {
12
+ const lower = field.toLowerCase();
13
+ return SENSITIVE_FIELD_HINTS.some((hint) => lower.includes(hint));
14
+ }
15
+
1
16
  module.exports = {
2
17
 
18
+ /**
19
+ * Look up the referenced model on the same connection this model was
20
+ * compiled on (models here are registered via `db.model(...)`, not the
21
+ * global `mongoose.model(...)` registry — see database/mongodb.js — so
22
+ * resolving by connection is required for this to ever find it).
23
+ *
24
+ * @param {String} refModelName mongoose ref (the "ref" schema option)
25
+ * @returns {Object|null}
26
+ */
27
+ _resolveRefModel(refModelName) {
28
+
29
+ try {
30
+ return (this.db && this.db.model(refModelName)) || mongoose.model(refModelName);
31
+ } catch {
32
+ return null;
33
+ }
34
+
35
+ },
36
+
37
+ /**
38
+ * A field is safe to expose through populate select when it's neither
39
+ * name-flagged as sensitive (SENSITIVE_FIELD_HINTS) nor marked
40
+ * `select: false` on the REFERENCED model's own schema. If the referenced
41
+ * model can't be resolved (e.g. in isolated unit tests), only the
42
+ * name-based check applies.
43
+ *
44
+ * @param {String} refModelName mongoose ref (the "ref" schema option)
45
+ * @param {String} field
46
+ * @returns {Boolean}
47
+ */
48
+ _isFieldSafeToExpose(refModelName, field) {
49
+
50
+ if (isSensitiveByName(field)) {
51
+ return false;
52
+ }
53
+
54
+ const RefModel = this._resolveRefModel(refModelName);
55
+ const refPath = RefModel && RefModel.schema.paths[field];
56
+
57
+ if (refPath && refPath.options && refPath.options.select === false) {
58
+ return false;
59
+ }
60
+
61
+ return true;
62
+
63
+ },
64
+
3
65
  /**
4
66
  * Parse the populate param into one entry per relation: `name` (trimmed,
5
67
  * lowercased) plus an optional `fields` list. Syntax: relations are
@@ -103,7 +165,28 @@ module.exports = {
103
165
  const populateProps = { path: field };
104
166
 
105
167
  if (entry.fields && entry.fields.length > 0) {
106
- populateProps.select = entry.fields.join(' ');
168
+
169
+ // Explicit field list: keep only what's safe, as a pure inclusion
170
+ // select. If everything requested turns out sensitive, fall back
171
+ // to "_id" only — never to the unfiltered full document.
172
+ const safeFields = entry.fields.filter((f) => this._isFieldSafeToExpose(ref, f));
173
+ populateProps.select = safeFields.length > 0 ? safeFields.join(' ') : '_id';
174
+
175
+ } else {
176
+
177
+ // Full-doc populate: still must not leak sensitive fields, so
178
+ // build an exclusion select for whatever the ref schema/name-hints
179
+ // flag on that model — skipped only if nothing needs excluding.
180
+ const RefModel = this._resolveRefModel(ref);
181
+
182
+ const toExclude = RefModel
183
+ ? Object.keys(RefModel.schema.paths).filter((f) => !this._isFieldSafeToExpose(ref, f))
184
+ : [];
185
+
186
+ if (toExclude.length > 0) {
187
+ populateProps.select = toExclude.map((f) => `-${f}`).join(' ');
188
+ }
189
+
107
190
  }
108
191
 
109
192
  return populateProps;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vulkano/core",
3
- "version": "1.24.0",
3
+ "version": "1.24.2",
4
4
  "description": "A MVC framework using Express 4",
5
5
  "license": "MIT",
6
6
  "author": "Vulkano Team",
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Exposes i18next translation as a view helper.
3
+ * Not the raw `i18n` global: Handlebars helpers must be callable functions,
4
+ * not objects with methods — {{ i18n.t('key') }} works in Nunjucks but
5
+ * throws in Handlebars ("fn is not a function") since its helper wrapper
6
+ * invokes whatever is registered directly.
7
+ *
8
+ * Usage:
9
+ * Nunjucks: {{ t('key') }}
10
+ * Handlebars: {{t "key"}}
11
+ */
12
+ module.exports = (key, options) => i18n.t(key, options);