parse
Version:
Parse JavaScript SDK
576 lines (550 loc) • 21.4 kB
JavaScript
"use strict";
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/map"));
var _entries = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/entries"));
var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
var _slice = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/slice"));
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var _every = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/every"));
var _keys = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/keys"));
var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));
var _ParseRole = _interopRequireDefault(require("./ParseRole"));
var _ParseUser = _interopRequireDefault(require("./ParseUser"));
const PUBLIC_KEY = '*';
const VALID_PERMISSIONS = new _map.default();
VALID_PERMISSIONS.set('get', {});
VALID_PERMISSIONS.set('find', {});
VALID_PERMISSIONS.set('count', {});
VALID_PERMISSIONS.set('create', {});
VALID_PERMISSIONS.set('update', {});
VALID_PERMISSIONS.set('delete', {});
VALID_PERMISSIONS.set('addField', {});
const VALID_PERMISSIONS_EXTENDED = new _map.default();
VALID_PERMISSIONS_EXTENDED.set('protectedFields', {});
/**
* Creates a new CLP.
* If no argument is given, the CLP has no permissions for anyone.
* If the argument is a Parse.User or Parse.Role, the CLP will have read and write
* permission for only that user or role.
* If the argument is any other JSON object, that object will be interpretted
* as a serialized CLP created with toJSON().
*
* <p>A CLP, or Class Level Permissions can be added to any
* <code>Parse.Schema</code> to restrict access to only a subset of users
* of your application.</p>
*
* <p>
* For get/count/find/create/update/delete/addField using the following functions:
*
* Entity is type Parse.User or Parse.Role or string
* Role is type Parse.Role or Name of Parse.Role
*
* getGetRequiresAuthentication()
* setGetRequiresAuthentication(allowed: boolean)
* getGetPointerFields()
* setGetPointerFields(pointerFields: string[])
* getGetAccess(entity: Entity)
* setGetAccess(entity: Entity, allowed: boolean)
* getPublicGetAccess()
* setPublicGetAccess(allowed: boolean)
* getRoleGetAccess(role: Role)
* setRoleGetAccess(role: Role, allowed: boolean)
* getFindRequiresAuthentication()
* setFindRequiresAuthentication(allowed: boolean)
* getFindPointerFields()
* setFindPointerFields(pointerFields: string[])
* getFindAccess(entity: Entity)
* setFindAccess(entity: Entity, allowed: boolean)
* getPublicFindAccess()
* setPublicFindAccess(allowed: boolean)
* getRoleFindAccess(role: Role)
* setRoleFindAccess(role: Role, allowed: boolean)
* getCountRequiresAuthentication()
* setCountRequiresAuthentication(allowed: boolean)
* getCountPointerFields()
* setCountPointerFields(pointerFields: string[])
* getCountAccess(entity: Entity)
* setCountAccess(entity: Entity, allowed: boolean)
* getPublicCountAccess()
* setPublicCountAccess(allowed: boolean)
* getRoleCountAccess(role: Role)
* setRoleCountAccess(role: Role, allowed: boolean)
* getCreateRequiresAuthentication()
* setCreateRequiresAuthentication(allowed: boolean)
* getCreatePointerFields()
* setCreatePointerFields(pointerFields: string[])
* getCreateAccess(entity: Entity)
* setCreateAccess(entity: Entity, allowed: boolean)
* getPublicCreateAccess()
* setPublicCreateAccess(allowed: Boolean)
* getRoleCreateAccess(role: Role)
* setRoleCreateAccess(role: Role, allowed: boolean)
* getUpdateRequiresAuthentication()
* setUpdateRequiresAuthentication(allowed: boolean)
* getUpdatePointerFields()
* setUpdatePointerFields(pointerFields: string[])
* getUpdateAccess(entity: Entity)
* setUpdateAccess(entity: Entity, allowed: boolean)
* getPublicUpdateAccess()
* setPublicUpdateAccess(allowed: boolean)
* getRoleUpdateAccess(role: Role)
* setRoleUpdateAccess(role: Role, allowed: boolean)
* getDeleteRequiresAuthentication()
* setDeleteRequiresAuthentication(allowed: boolean)
* getDeletePointerFields()
* setDeletePointerFields(pointerFields: string[])
* getDeleteAccess(entity: Entity)
* setDeleteAccess(entity: Entity, allowed: boolean)
* getPublicDeleteAccess()
* setPublicDeleteAccess(allowed: boolean)
* getRoleDeleteAccess(role: Role)
* setRoleDeleteAccess(role: Role, allowed: boolean)
* getAddFieldRequiresAuthentication()
* setAddFieldRequiresAuthentication(allowed: boolean)
* getAddFieldPointerFields()
* setAddFieldPointerFields(pointerFields: string[])
* getAddFieldAccess(entity: Entity)
* setAddFieldAccess(entity: Entity, allowed: boolean)
* getPublicAddFieldAccess()
* setPublicAddFieldAccess(allowed: boolean)
* getRoleAddFieldAccess(role: Role)
* setRoleAddFieldAccess(role: Role, allowed: boolean)
* </p>
*
* @alias Parse.CLP
*/
class ParseCLP {
/**
* @param {(Parse.User | Parse.Role | object)} userId The user to initialize the CLP for
*/
constructor(userId) {
(0, _defineProperty2.default)(this, "permissionsMap", void 0);
this.permissionsMap = {};
// Initialize permissions Map with default permissions
for (const [operation, group] of (0, _entries.default)(VALID_PERMISSIONS).call(VALID_PERMISSIONS)) {
this.permissionsMap[operation] = (0, _assign.default)({}, group);
const action = operation.charAt(0).toUpperCase() + (0, _slice.default)(operation).call(operation, 1);
this[`get${action}RequiresAuthentication`] = function () {
return this._getAccess(operation, 'requiresAuthentication');
};
this[`set${action}RequiresAuthentication`] = function (allowed) {
this._setAccess(operation, 'requiresAuthentication', allowed);
};
this[`get${action}PointerFields`] = function () {
return this._getAccess(operation, 'pointerFields', false);
};
this[`set${action}PointerFields`] = function (pointerFields) {
this._setArrayAccess(operation, 'pointerFields', pointerFields);
};
this[`get${action}Access`] = function (entity) {
return this._getAccess(operation, entity);
};
this[`set${action}Access`] = function (entity, allowed) {
this._setAccess(operation, entity, allowed);
};
this[`getPublic${action}Access`] = function () {
return this[`get${action}Access`](PUBLIC_KEY);
};
this[`setPublic${action}Access`] = function (allowed) {
this[`set${action}Access`](PUBLIC_KEY, allowed);
};
this[`getRole${action}Access`] = function (role) {
return this[`get${action}Access`](this._getRoleName(role));
};
this[`setRole${action}Access`] = function (role, allowed) {
this[`set${action}Access`](this._getRoleName(role), allowed);
};
}
// Initialize permissions Map with default extended permissions
for (const [operation, group] of (0, _entries.default)(VALID_PERMISSIONS_EXTENDED).call(VALID_PERMISSIONS_EXTENDED)) {
this.permissionsMap[operation] = (0, _assign.default)({}, group);
}
if (userId && typeof userId === 'object') {
if (userId instanceof _ParseUser.default) {
this.setReadAccess(userId, true);
this.setWriteAccess(userId, true);
} else if (userId instanceof _ParseRole.default) {
this.setRoleReadAccess(userId, true);
this.setRoleWriteAccess(userId, true);
} else {
for (const permission in userId) {
var _context;
const users = userId[permission];
const isValidPermission = !!VALID_PERMISSIONS.get(permission);
const isValidPermissionExtended = !!VALID_PERMISSIONS_EXTENDED.get(permission);
const isValidGroupPermission = (0, _includes.default)(_context = ['readUserFields', 'writeUserFields']).call(_context, permission);
if (typeof permission !== 'string' || !(isValidPermission || isValidPermissionExtended || isValidGroupPermission)) {
throw new TypeError('Tried to create an CLP with an invalid permission type.');
}
if (isValidGroupPermission) {
if ((0, _every.default)(users).call(users, pointer => typeof pointer === 'string')) {
this.permissionsMap[permission] = users;
continue;
} else {
throw new TypeError('Tried to create an CLP with an invalid permission value.');
}
}
for (const user in users) {
const allowed = users[user];
if (typeof allowed !== 'boolean' && !isValidPermissionExtended && user !== 'pointerFields') {
throw new TypeError('Tried to create an CLP with an invalid permission value.');
}
this.permissionsMap[permission][user] = allowed;
}
}
}
} else if (typeof userId === 'function') {
throw new TypeError('ParseCLP constructed with a function. Did you forget ()?');
}
}
/**
* Returns a JSON-encoded version of the CLP.
*
* @returns {object}
*/
toJSON() {
return {
...this.permissionsMap
};
}
/**
* Returns whether this CLP is equal to another object
*
* @param other The other object to compare to
* @returns {boolean}
*/
equals(other) {
if (!(other instanceof ParseCLP)) {
return false;
}
const permissions = (0, _keys.default)(this.permissionsMap);
const otherPermissions = (0, _keys.default)(other.permissionsMap);
if (permissions.length !== otherPermissions.length) {
return false;
}
for (const permission in this.permissionsMap) {
if (!other.permissionsMap[permission]) {
return false;
}
const users = (0, _keys.default)(this.permissionsMap[permission]);
const otherUsers = (0, _keys.default)(other.permissionsMap[permission]);
if (users.length !== otherUsers.length) {
return false;
}
for (const user in this.permissionsMap[permission]) {
if (!other.permissionsMap[permission][user]) {
return false;
}
if (this.permissionsMap[permission][user] !== other.permissionsMap[permission][user]) {
return false;
}
}
}
return true;
}
_getRoleName(role) {
let name = role;
if (role instanceof _ParseRole.default) {
// Normalize to the String name
name = role.getName();
}
if (typeof name !== 'string') {
throw new TypeError('role must be a Parse.Role or a String');
}
return `role:${name}`;
}
_parseEntity(entity) {
let userId = entity;
if (userId instanceof _ParseUser.default) {
userId = userId.id;
if (!userId) {
throw new Error('Cannot get access for a Parse.User without an id.');
}
} else if (userId instanceof _ParseRole.default) {
userId = this._getRoleName(userId);
}
if (typeof userId !== 'string') {
throw new TypeError('userId must be a string.');
}
return userId;
}
_setAccess(permission, userId, allowed) {
userId = this._parseEntity(userId);
if (typeof allowed !== 'boolean') {
throw new TypeError('allowed must be either true or false.');
}
const permissions = this.permissionsMap[permission][userId];
if (!permissions) {
if (!allowed) {
// The user already doesn't have this permission, so no action is needed
return;
} else {
this.permissionsMap[permission][userId] = {};
}
}
if (allowed) {
this.permissionsMap[permission][userId] = true;
} else {
delete this.permissionsMap[permission][userId];
}
}
_getAccess(permission, userId) {
let returnBoolean = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
userId = this._parseEntity(userId);
const permissions = this.permissionsMap[permission][userId];
if (returnBoolean) {
if (!permissions) {
return false;
}
return !!this.permissionsMap[permission][userId];
}
return permissions;
}
_setArrayAccess(permission, userId, fields) {
userId = this._parseEntity(userId);
const permissions = this.permissionsMap[permission][userId];
if (!permissions) {
this.permissionsMap[permission][userId] = [];
}
if (!fields || (0, _isArray.default)(fields) && fields.length === 0) {
delete this.permissionsMap[permission][userId];
} else if ((0, _isArray.default)(fields) && (0, _every.default)(fields).call(fields, field => typeof field === 'string')) {
this.permissionsMap[permission][userId] = fields;
} else {
throw new TypeError('fields must be an array of strings or undefined.');
}
}
_setGroupPointerPermission(operation, pointerFields) {
const fields = this.permissionsMap[operation];
if (!fields) {
this.permissionsMap[operation] = [];
}
if (!pointerFields || (0, _isArray.default)(pointerFields) && pointerFields.length === 0) {
delete this.permissionsMap[operation];
} else if ((0, _isArray.default)(pointerFields) && (0, _every.default)(pointerFields).call(pointerFields, field => typeof field === 'string')) {
this.permissionsMap[operation] = pointerFields;
} else {
throw new TypeError(`${operation}.pointerFields must be an array of strings or undefined.`);
}
}
_getGroupPointerPermissions(operation) {
return this.permissionsMap[operation] || [];
}
/**
* Sets user pointer fields to allow permission for get/count/find operations.
*
* @param {string[]} pointerFields User pointer fields
*/
setReadUserFields(pointerFields) {
this._setGroupPointerPermission('readUserFields', pointerFields);
}
/**
* @returns {string[]} User pointer fields
*/
getReadUserFields() {
return this._getGroupPointerPermissions('readUserFields') || [];
}
/**
* Sets user pointer fields to allow permission for create/delete/update/addField operations
*
* @param {string[]} pointerFields User pointer fields
*/
setWriteUserFields(pointerFields) {
this._setGroupPointerPermission('writeUserFields', pointerFields);
}
/**
* @returns {string[]} User pointer fields
*/
getWriteUserFields() {
return this._getGroupPointerPermissions('writeUserFields') || [];
}
/**
* Sets whether the given user is allowed to retrieve fields from this class.
*
* @param userId An instance of Parse.User or its objectId.
* @param {string[]} fields fields to be protected
*/
setProtectedFields(userId, fields) {
this._setArrayAccess('protectedFields', userId, fields);
}
/**
* Returns array of fields are accessable to this user.
*
* @param userId An instance of Parse.User or its objectId, or a Parse.Role.
* @returns {string[]}
*/
getProtectedFields(userId) {
return this._getAccess('protectedFields', userId, false);
}
/**
* Sets whether the given user is allowed to read from this class.
*
* @param userId An instance of Parse.User or its objectId.
* @param {boolean} allowed whether that user should have read access.
*/
setReadAccess(userId, allowed) {
this._setAccess('find', userId, allowed);
this._setAccess('get', userId, allowed);
this._setAccess('count', userId, allowed);
}
/**
* Get whether the given user id is *explicitly* allowed to read from this class.
* Even if this returns false, the user may still be able to access it if
* getPublicReadAccess returns true or a role that the user belongs to has
* write access.
*
* @param userId An instance of Parse.User or its objectId, or a Parse.Role.
* @returns {boolean}
*/
getReadAccess(userId) {
return this._getAccess('find', userId) && this._getAccess('get', userId) && this._getAccess('count', userId);
}
/**
* Sets whether the given user id is allowed to write to this class.
*
* @param userId An instance of Parse.User or its objectId, or a Parse.Role..
* @param {boolean} allowed Whether that user should have write access.
*/
setWriteAccess(userId, allowed) {
this._setAccess('create', userId, allowed);
this._setAccess('update', userId, allowed);
this._setAccess('delete', userId, allowed);
this._setAccess('addField', userId, allowed);
}
/**
* Gets whether the given user id is *explicitly* allowed to write to this class.
* Even if this returns false, the user may still be able to write it if
* getPublicWriteAccess returns true or a role that the user belongs to has
* write access.
*
* @param userId An instance of Parse.User or its objectId, or a Parse.Role.
* @returns {boolean}
*/
getWriteAccess(userId) {
return this._getAccess('create', userId) && this._getAccess('update', userId) && this._getAccess('delete', userId) && this._getAccess('addField', userId);
}
/**
* Sets whether the public is allowed to read from this class.
*
* @param {boolean} allowed
*/
setPublicReadAccess(allowed) {
this.setReadAccess(PUBLIC_KEY, allowed);
}
/**
* Gets whether the public is allowed to read from this class.
*
* @returns {boolean}
*/
getPublicReadAccess() {
return this.getReadAccess(PUBLIC_KEY);
}
/**
* Sets whether the public is allowed to write to this class.
*
* @param {boolean} allowed
*/
setPublicWriteAccess(allowed) {
this.setWriteAccess(PUBLIC_KEY, allowed);
}
/**
* Gets whether the public is allowed to write to this class.
*
* @returns {boolean}
*/
getPublicWriteAccess() {
return this.getWriteAccess(PUBLIC_KEY);
}
/**
* Sets whether the public is allowed to protect fields in this class.
*
* @param {string[]} fields
*/
setPublicProtectedFields(fields) {
this.setProtectedFields(PUBLIC_KEY, fields);
}
/**
* Gets whether the public is allowed to read fields from this class.
*
* @returns {string[]}
*/
getPublicProtectedFields() {
return this.getProtectedFields(PUBLIC_KEY);
}
/**
* Gets whether users belonging to the given role are allowed
* to read from this class. Even if this returns false, the role may
* still be able to write it if a parent role has read access.
*
* @param role The name of the role, or a Parse.Role object.
* @returns {boolean} true if the role has read access. false otherwise.
* @throws {TypeError} If role is neither a Parse.Role nor a String.
*/
getRoleReadAccess(role) {
return this.getReadAccess(this._getRoleName(role));
}
/**
* Gets whether users belonging to the given role are allowed
* to write to this user. Even if this returns false, the role may
* still be able to write it if a parent role has write access.
*
* @param role The name of the role, or a Parse.Role object.
* @returns {boolean} true if the role has write access. false otherwise.
* @throws {TypeError} If role is neither a Parse.Role nor a String.
*/
getRoleWriteAccess(role) {
return this.getWriteAccess(this._getRoleName(role));
}
/**
* Sets whether users belonging to the given role are allowed
* to read from this class.
*
* @param role The name of the role, or a Parse.Role object.
* @param {boolean} allowed Whether the given role can read this object.
* @throws {TypeError} If role is neither a Parse.Role nor a String.
*/
setRoleReadAccess(role, allowed) {
this.setReadAccess(this._getRoleName(role), allowed);
}
/**
* Sets whether users belonging to the given role are allowed
* to write to this class.
*
* @param role The name of the role, or a Parse.Role object.
* @param {boolean} allowed Whether the given role can write this object.
* @throws {TypeError} If role is neither a Parse.Role nor a String.
*/
setRoleWriteAccess(role, allowed) {
this.setWriteAccess(this._getRoleName(role), allowed);
}
/**
* Gets whether users belonging to the given role are allowed
* to count to this user. Even if this returns false, the role may
* still be able to count it if a parent role has count access.
*
* @param role The name of the role, or a Parse.Role object.
* @returns {string[]}
* @throws {TypeError} If role is neither a Parse.Role nor a String.
*/
getRoleProtectedFields(role) {
return this.getProtectedFields(this._getRoleName(role));
}
/**
* Sets whether users belonging to the given role are allowed
* to set access field in this class.
*
* @param role The name of the role, or a Parse.Role object.
* @param {string[]} fields Fields to be protected by Role.
* @throws {TypeError} If role is neither a Parse.Role nor a String.
*/
setRoleProtectedFields(role, fields) {
this.setProtectedFields(this._getRoleName(role), fields);
}
}
var _default = exports.default = ParseCLP;