<commit_before>'use strict';

var validator = require('ajv');
var debug = require('debug')('canornot');
//var validator = require('is-my-json-valid');
//var validator = require('jsen');

var _ = {
    defaultsDeep: require('lodash.defaultsdeep'),
    omit: require('lodash.omit')
};

function PermissionError(message) {
    Error.captureStackTrace(this, this.constructor);
    this.name = this.constructor.name;
    this.message = message;
}

require('util').inherits(PermissionError, Error);

module.exports = function Canoronot(options) {

    options = _.defaultsDeep(options || {}, {
        rejectOnError: true,
        rejectOnPermissionDenied: true,
        returnSchemas: false
    });

    /**
     * @returns {Promise<Object>}
     */
    function getPolicySchema() {
        if (typeof options.policySchema === 'function') {

            // accepts a callback arguments
            if (options.policySchema.length === 1) {
                return new Promise(function (resolve, reject) {

                    return options.policySchema(function (result) {
                        if (result instanceof Error) {
                            reject(result);
                        } else {
                            resolve(result);
                        }
                    });
                });
            } else {
                return Promise.resolve(options.policySchema());
            }

        } else if (typeof options.policySchema === 'object' && typeof options.policySchema.then === 'function') {
            return options.policySchema;
        } else {
            return Promise.resolve(options.policySchema);
        }
    }

    /**
     * @returns {Promise<Object>}
     */
    function getActorSchema() {
        if (typeof options.actorSchema === 'function') {

            // accepts a callback arguments
            if (options.actorSchema.length === 1) {
                return new Promise(function (resolve, reject) {

                    return options.actorSchema(function (result) {
                        if (result instanceof Error) {
                            reject(result);
                        } else {
                            resolve(result);
                        }
                    });
                });
            } else {
                return Promise.resolve(options.actorSchema());
            }

        } else if (typeof options.actorSchema === 'object' && typeof options.actorSchema.then === 'function') {
            return options.actorSchema;
        } else {
            return Promise.resolve(options.actorSchema);
        }
    }

    /**
     * @returns {Promise}
     */
    function init() {

        return Promise.resolve();

        // return Promise.all([getActorSchema(), getPolicySchema()])
        //     .then(function (results) {
        //
        //         var actorSchema = results[0];
        //         var policySchema = results[1];
        //
        //         if (typeof actorSchema !== 'object') {
        //             throw new TypeError('Actor Schema must be an object or a function/promise that returns an object. Saw ' + typeof actorSchema);
        //         }
        //
        //         if (typeof policySchema !== 'object') {
        //             throw new TypeError('Policy Schema must be an object or a function/promise that returns an object. Saw ' + typeof policySchema);
        //         }
        //
        //         if (!loaded) {
        //             try {
        //                 console.log('adding actor schema');
        //                 validator.addSchema(actorSchema, 'actor');
        //                 console.log('adding policy schema');
        //                 validator.addSchema(policySchema, 'policy');
        //                 loaded = true;
        //             } catch (err) {
        //                 console.log('kakked it', err.message);
        //                 throw new Error('Failed to add policy or actor schema: ' + err.message);
        //
        //             }
        //         } else {
        //             console.log('policies already loaded');
        //         }
        //
        //     });
    }

    /**
     * @param {String} permission
     * @param {*} data
     * @returns {Promise.<Boolean>}
     */
    this.can = function (permission, data) {

        if (typeof permission !== 'string') {
            return Promise.reject(new TypeError('Permission must be a string'));
        }

        return init()
            .then(function () {

                // AJV
                return Promise.all([getActorSchema(), getPolicySchema()])
                    .then(function (schemas) {

                        var actorSchema = schemas[0];
                        var policySchema = schemas[1];

                        if (typeof actorSchema !== 'object') {
                            throw new TypeError('Actor Schema must be an object or a function/promise that returns an object. Saw ' + typeof actorSchema);
                        }

                        if (typeof policySchema !== 'object') {
                            throw new TypeError('Policy Schema must be an object or a function/promise that returns an object. Saw ' + typeof policySchema);
                        }

                        var ajv = validator({
                            breakOnError: true
                        });

                        ajv.addSchema(actorSchema, 'actor');
                        ajv.addSchema(policySchema, 'policy');

                        var validate = ajv.compile({
                            $ref: 'policy#/properties/' + permission
                        });

                        var valid = validate(data);

                        debug('Permission `%s` against data `%s` - allowed: `%s`', permission, JSON.stringify(data), valid);

                        debug('rejectOnPermissionDenied: `%s`', options.rejectOnPermissionDenied);

                        if (options.rejectOnPermissionDenied === true) {
                            if (!valid) {
                                debug('Throwing PermissionError', validate.errors);
                                var err = new PermissionError('Permission Denied for `' + permission + '` against `' + JSON.stringify(data) + '`');
                                err.errors = validate.errors;
                                throw err;
                            } else {
                                if (options.returnSchemas) {
                                    return {
                                        actor: actorSchema,
                                        policy: policySchema
                                    };
                                } else {
                                    return valid;<commit_msg>Flip the way the schema is compared against the data this now allows things like patterProperties for the permission<commit_after>'use strict';

var validator = require('ajv');
var debug = require('debug')('canornot');
//var validator = require('is-my-json-valid');
//var validator = require('jsen');

var _ = {
    defaultsDeep: require('lodash.defaultsdeep'),
    omit: require('lodash.omit')
};

function PermissionError(message) {
    Error.captureStackTrace(this, this.constructor);
    this.name = this.constructor.name;
    this.message = message;
}

require('util').inherits(PermissionError, Error);

module.exports = function Canoronot(options) {

    options = _.defaultsDeep(options || {}, {
        rejectOnError: true,
        rejectOnPermissionDenied: true,
        returnSchemas: false
    });

    /**
     * @returns {Promise<Object>}
     */
    function getPolicySchema() {
        if (typeof options.policySchema === 'function') {

            // accepts a callback arguments
            if (options.policySchema.length === 1) {
                return new Promise(function (resolve, reject) {

                    return options.policySchema(function (result) {
                        if (result instanceof Error) {
                            reject(result);
                        } else {
                            resolve(result);
                        }
                    });
                });
            } else {
                return Promise.resolve(options.policySchema());
            }

        } else if (typeof options.policySchema === 'object' && typeof options.policySchema.then === 'function') {
            return options.policySchema;
        } else {
            return Promise.resolve(options.policySchema);
        }
    }

    /**
     * @returns {Promise<Object>}
     */
    function getActorSchema() {
        if (typeof options.actorSchema === 'function') {

            // accepts a callback arguments
            if (options.actorSchema.length === 1) {
                return new Promise(function (resolve, reject) {

                    return options.actorSchema(function (result) {
                        if (result instanceof Error) {
                            reject(result);
                        } else {
                            resolve(result);
                        }
                    });
                });
            } else {
                return Promise.resolve(options.actorSchema());
            }

        } else if (typeof options.actorSchema === 'object' && typeof options.actorSchema.then === 'function') {
            return options.actorSchema;
        } else {
            return Promise.resolve(options.actorSchema);
        }
    }

    /**
     * @returns {Promise}
     */
    function init() {

        return Promise.resolve();

        // return Promise.all([getActorSchema(), getPolicySchema()])
        //     .then(function (results) {
        //
        //         var actorSchema = results[0];
        //         var policySchema = results[1];
        //
        //         if (typeof actorSchema !== 'object') {
        //             throw new TypeError('Actor Schema must be an object or a function/promise that returns an object. Saw ' + typeof actorSchema);
        //         }
        //
        //         if (typeof policySchema !== 'object') {
        //             throw new TypeError('Policy Schema must be an object or a function/promise that returns an object. Saw ' + typeof policySchema);
        //         }
        //
        //         if (!loaded) {
        //             try {
        //                 console.log('adding actor schema');
        //                 validator.addSchema(actorSchema, 'actor');
        //                 console.log('adding policy schema');
        //                 validator.addSchema(policySchema, 'policy');
        //                 loaded = true;
        //             } catch (err) {
        //                 console.log('kakked it', err.message);
        //                 throw new Error('Failed to add policy or actor schema: ' + err.message);
        //
        //             }
        //         } else {
        //             console.log('policies already loaded');
        //         }
        //
        //     });
    }

    /**
     * @param {String} permission
     * @param {*} data
     * @returns {Promise.<Boolean>}
     */
    this.can = function (permission, data) {

        if (typeof permission !== 'string') {
            return Promise.reject(new TypeError('Permission must be a string'));
        }

        return init()
            .then(function () {

                // AJV
                return Promise.all([getActorSchema(), getPolicySchema()])
                    .then(function (schemas) {

                        var actorSchema = schemas[0];
                        var policySchema = schemas[1];

                        if (typeof actorSchema !== 'object') {
                            throw new TypeError('Actor Schema must be an object or a function/promise that returns an object. Saw ' + typeof actorSchema);
                        }

                        if (typeof policySchema !== 'object') {
                            throw new TypeError('Policy Schema must be an object or a function/promise that returns an object. Saw ' + typeof policySchema);
                        }

                        var ajv = validator({
                            missingRefs: 'fail',
                            breakOnError: true
                        });

                        ajv.addSchema(actorSchema, 'actor');
                        //ajv.addSchema(policySchema, 'policy');

                        // var validate = ajv.compile({
                        //     $ref: 'policy#/properties/' + permission
                        // });

                        // var valid = validate(data);
                        //
                        // var validate = ajv.compile({
                        //     $ref: 'policy#/properties/' + permission
                        // });

                        policySchema.additionalProperties = false;

                        var valid = ajv.validate(policySchema, {
                            [permission]: data
                        });

                        debug('policySchema', policySchema);
                        debug('actorSchema', actorSchema);
                        debug('Permission data', JSON.stringify({
                            [permission]: data
                        }));
                        debug('Permission allowed/valid?', valid);

                        if (options.rejectOnPermissionDenied === true) {
                            if (!valid) {
                                debug('Throwing PermissionError', ajv.errors);
                                var err = new PermissionError('Permission Denied for `' + permission + '` against `' + JSON.stringify(data) + '`');
                                err.errors = ajv.errors;
                                throw err;
                            } else {
                                if (options.returnSchemas) {
                                    return {
                                        actor: actorSchema,
                                        policy: policySchema
                                    };
                                } else {
                                    return valid;
{'fraction_non_alphanumeric': 0.10888252148997135, 'fraction_numerical': 0.0008386330281640926, 'mean_word_length': 1.176425855513308, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3771691', 'n_tokens_mistral': 3270, 'n_tokens_neox': 3095, 'n_words': 773}