Skip to content

Commit 0904a18

Browse files
committed
feat(query): add sanitizeProjection method to query for better docs
1 parent eb7deb0 commit 0904a18

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

lib/query.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,59 @@ Query.prototype.select = function select() {
11421142
throw new TypeError('Invalid select() argument. Must be string or object.');
11431143
};
11441144

1145+
/**
1146+
* Sets this query's `sanitizeProjection` option. If set, `sanitizeProjection` does
1147+
* two things:
1148+
*
1149+
* 1. Enforces that projection values are numbers, not strings.
1150+
* 2. Prevents using `+` syntax to override properties that are deselected by default.
1151+
*
1152+
* With `sanitizeProjection()`, you can pass potentially untrusted user data to `.select()`.
1153+
*
1154+
* #### Example
1155+
*
1156+
* const userSchema = new Schema({
1157+
* name: String,
1158+
* password: { type: String, select: false }
1159+
* });
1160+
* const UserModel = mongoose.model('User', userSchema);
1161+
* const { _id } = await UserModel.create({ name: 'John', password: 'secret' })
1162+
*
1163+
* // The MongoDB server has special handling for string values that start with '$'
1164+
* // in projections, which can lead to unexpected leaking of sensitive data.
1165+
* let doc = await UserModel.findOne().select({ name: '$password' });
1166+
* doc.name; // 'secret'
1167+
* doc.password; // undefined
1168+
*
1169+
* // With `sanitizeProjection`, Mongoose forces all projection values to be numbers
1170+
* doc = await UserModel.findOne().sanitizeProjection(true).select({ name: '$password' });
1171+
* doc.name; // 'John'
1172+
* doc.password; // undefined
1173+
*
1174+
* // By default, Mongoose supports projecting in `password` using `+password`
1175+
* doc = await UserModel.findOne().select('+password');
1176+
* doc.password; // 'secret'
1177+
*
1178+
* // With `sanitizeProjection`, Mongoose prevents projecting in `password` and other
1179+
* // fields that have `select: false` in the schema.
1180+
* doc = await UserModel.findOne().sanitizeProjection(true).select('+password');
1181+
* doc.password; // undefined
1182+
*
1183+
* @method sanitizeProjection
1184+
* @memberOf Query
1185+
* @instance
1186+
* @param {Boolean} value
1187+
* @return {Query} this
1188+
* @see sanitizeProjection https://thecodebarbarian.com/whats-new-in-mongoose-5-13-sanitizeprojection.html
1189+
* @api public
1190+
*/
1191+
1192+
Query.prototype.sanitizeProjection = function sanitizeProjection(value) {
1193+
this._mongooseOptions.sanitizeProjection = value;
1194+
1195+
return this;
1196+
};
1197+
11451198
/**
11461199
* Determines the MongoDB nodes from which to read.
11471200
*

types/query.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,11 @@ declare module 'mongoose' {
716716
options?: QueryOptions<DocType> | null
717717
): QueryWithHelpers<any, DocType, THelpers, RawDocType, 'replaceOne', TInstanceMethods>;
718718

719+
/**
720+
* Sets this query's `sanitizeProjection` option. With `sanitizeProjection()`, you can pass potentially untrusted user data to `.select()`.
721+
*/
722+
sanitizeProjection(value: boolean): this;
723+
719724
/** Specifies which document fields to include or exclude (also known as the query "projection") */
720725
select<RawDocTypeOverride extends { [P in keyof RawDocType]?: any } = {}>(
721726
arg: string | string[] | Record<string, number | boolean | string | object>

0 commit comments

Comments
 (0)