I am trying to implement a whitelist policy in OPA rego. The purpose of the policy is to block all attributes except for attributes that have been whitelisted. However, I cannot get it to work.
Here is my rego policy:
package play
whitelisted_attributes =
{
"foo.bar",
"hello.from.*.world"
}
default allow = false
default not_in_whitelist = true
not_in_whitelist {
whitelisted := {attr | attr := input.attributes[_]; glob.match(whitelisted_attributes[_], ["."], attr)}
count(whitelisted) == 0
}
allow {
not not_in_whitelist
}
Here is my input:
{
"attributes": [
"foo.bar"
]
}
Here is the output according to the Rego Playground:
{
"allow": false,
"not_in_whitelist": true,
"whitelisted_attributes": [
"foo.bar",
"hello.from.*.world"
]
}
As you can see, "allow" should be true since the input is found in the whitelist. Also, "not_in_whitelist" should be false since the input attribute is in the whitelist.
What's happening here is that since one of the elements is in the whitelist, the not_in_whitelist rule is going to evaluate to undefined (since that's what a rule where all conditions aren't met evaluates to).
Since not_in_whitelist evaluates to undefined, the rule will be assigned the default value of true:
default not_in_whitelist = true
The allow rule will then invert that in the not check, making the rule fail (since not true == false):
allow {
not not_in_whitelist
}
I'd suggest simply removing the default assignment for not_in_whitelist.
Thanks #Devoops for your tip. I went back to the Rego Playground and after much trial and error came up with a working policy. I'm posting it here for others with similar needs.
package play
default allow = false
default in_whitelist = false
whitelist =
{
"foo.bar",
"hello.from.*.world"
}
num_attributes := count(input.attributes)
in_whitelist {
glob.match(whitelist[_], ["."], input.attributes[_])
}
not_in_whitelist = result {
num_attributes == 1
result := (in_whitelist == false)
}
not_in_whitelist = result {
num_attributes > 1
whitelisted := {attr | attr := input.attributes[_]; glob.match(whitelist[_], ["."], attr)}
result := (count(whitelisted) < num_attributes)
}
allow {
not not_in_whitelist
}
deny[msg] {
not_in_whitelist
msg = sprintf("You are only allowed to modify the following whitelisted attributes: %v", [whitelist])
}
Related
I want always show compopent if logic one time is true.
I try add and set new var , but get "Unexpected side effect in "canShowAlways" computed property".
How i can do it in vue ?
<mycomp v-if="canShowAlways" />
data: function(){
return {
a: 0,
b: 4,
c: 1
d: 2,
isAlwaysShow: false
}
}
computed: {
canShowAlways() {
if(this.isAlwaysShow){
return true;
}
var isLast = this.a && this.b || this.c && this.d;
if(isLast){
this.isAlwaysShow = true;
return true;
}
return false;
},
In general, you should not edit other data in computed property.
This line this.isAlwaysShow = true; is most likely what causes the error that you see in your code.
If you really wanted to stick to the code you have above, then a quick solution would be to call a method that would change the value of this.isAlwaysShow.
Otherwise, you would set a watch as mentioned here.
There is most likely a better way to handle what you are trying to do but more information would need to be provided.
In for example Swift/iOS development, it's possible to differentiate builds for different environments with "flags" such as:
#if STAGING
// one set of logic here
#endif
#if PRODUCTION
// another set of logic here
#endif
Is it possible to achieve the same with a Vue.js project, and how would we go about doing it? I am aware of makes different routes conditionally available for different roles (which is also quite neat), but I am optimally looking for the option to differentiate on a source code level.
Hope someone has some great insights! It could include:
How to exclude parts of a file (such as the #if STAGING above) from a build target
How to exclude entire files from a build target
etc.
you have the ability to use this syntax
if(process.env.NODE_ENV === 'production') {
console.log("this is the prod env!!!!!!!!!!");
config.output.path = path.resolve(__dirname, "dist");
}
make sure that when you run the script with the correct env's for each environment (local, dev, staging, prod etc ..) :D
just change the vue-loader output.
the source code
<template v-if="process.env.NODE_ENV === 'development'">
development only
</template>
default output
var render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c(
"div",
{ attrs: { id: "app" } },
[
_vm.process.env.NODE_ENV === "development"
? [_vm._v(" development only ")]
: _vm._e(),
_c("router-view")
],
2
)
}
just use regex to replace _vm.process.env. by process.env is ok.
// webpack.config.js
module: {
rules: [{
// must set post
enforce: 'post',
test: /\.vue$/,
use: [{
loader: './myLoader'
}]
}]
}
// myLoader.js
module.exports = function (source, map) {
if (source.indexOf('_vm.process.env') > -1) {
source = source.replace(/_vm.process.env/g, 'process.env')
}
this.callback(
null,
source,
map
)
}
Final the vue-loader result change
var render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c(
"div",
{ attrs: { id: "app" } },
[
// change to true
true
? [_vm._v(" development only ")]
: undefined,
_c("router-view")
],
2
)
}
I have a custom validation in VeeValidate for EU Vat Numbers. It connects to our API, which routes it to the VIES webservice. This webservice is very unstable though, and a lot of errors occur, which results in a 500 response. Right now, I return false when an error has occured, but I was wondering if there was a way to warn the user that something went wrong instead of saying the value is invalid?
Validator.extend('vat', {
getMessage: field => 'The ' + field + ' is invalid.',
validate: async (value) => {
let countryCode = value.substr(0, 2)
let number = value.substr(2, value.length - 2)
try {
const {status, data} = await axios.post('/api/euvat', {countryCode: countryCode, vatNumber: number})
return status === 200 ? data.success : false
} catch (e) {
return false
}
},
}, {immediate: false})
EDIT: Changed code with try-catch.
You can use:
try {
your logic
}
catch(error) {
warn user if API brokes (and maybe inform them to try again)
}
finally {
this is optional (you can for example turn of your loader here)
}
In your case try catch finally block would go into validate method
OK, first of all I don't think that informing user about broken API in a form validation error message is a good idea :-| (I'd use snackbar or something like that ;) )
any way, maybe this will help you out:
I imagine you are extending your form validation in created hook so maybe getting message conditionaly to variable would work. Try this:
created() {
+ let errorOccured = false;
Validator.extend('vat', {
- getMessage: field => 'The ' + field + ' is invalid.',
+ getMessage: field => errorOccured ? `Trouble with API` : `The ${field} is invalid.`,
validate: async (value) => {
let countryCode = value.substr(0, 2)
let number = value.substr(2, value.length - 2)
const {status, data} = await axios.post('/api/euvat', {countryCode: countryCode, vatNumber: number})
+ errorOccured = status !== 200;
return status === 200 ? data.success : false;
},
}, {immediate: false})
}
After searching a lot, I found the best approach to do this. You just have to return an object instead of a boolean with these values:
{
valid: false,
data: { message: 'Some error occured.' }
}
It will override the default message. If you want to return an object with the default message, you can just set the data value to undefined.
Here is a veeValidate v3 version for this:
import { extend } from 'vee-validate';
extend('vat', async function(value) {
const {status, data} = await axios.post('/api/validate-vat', {vat: value})
if (status === 200 && data.valid) {
return true;
}
return 'The {_field_} field must be a valid vat number';
});
This assumes your API Endpoint is returning json: { valid: true } or { valid: false }
I am working on a liking/unliking button, which works as expected, except that for some reason, it does not seem to be able to check if a user has already liked a post.
Here is my computed value where I attempt to perform the check:
isLikedByUser() {
console.log('this.likes count is: ', this.likes.length)
console.log('current user.id is: ', this.me.id)
console.log('these are the likes in the computed value: ', this.likes)
for(const like of this.likes) {
if (like.user.id === this.me.id) {
console.log('true')
return true
} else {
console.log('false')
return false
}
}
}
All of the console.log except the final true/false (which always returns false) work.
here is the console output:
these are the likes: (4) [{…}, {…}, {…}, {…}]
Post.vue?4c00:79 this.likes count is: 4
Post.vue?4c00:80 current user.id is: 1
Post.vue?4c00:81 these are the likes in the computed value: (4) [{…}, {…}, {…}, {…}, __ob__: Observer]
Post.vue?4c00:87 false
The 2nd element of this array is a "like" with users_id = 1, which should match the current user.id and result in a "true" output, so my thought is that the loop is stopping at the first element, but I am not sure.
It's a typo, you should be checking for like.user_id === this.me.id.
for(const like of this.likes) {
if (like.user_id === this.me.id) {
console.log('true')
return true
} else {
console.log('false')
return false
}
}
Also, you can make a less verbose version of the above code by using the some function of JavaScript:
if (this.likes.some(e => e.user_id == this.me.id)) {
console.log(true)
return true
} else {
console.log(false)
return false
}
for anyone coming to this, I figured out the problem. Loop was ending on return, so when the result was false, the for loop would exit before it had checked all of them to find the like that was by the current user. The solution is as follows:
isLikedByUser() {
for(const like of this.likes) {
if (like.user.id === this.me.id) {
return true
}
}
return false
}
Using Mongoose model method findOne, I receive a model. Now I want to custom that model before sending it to client, augmenting several attributes into that model.
However, the only way I found for the moment is to turn that model into plain object and augment that object.
I don't know is there any better way doing it?
Here is my lengthy code for that simple purpose:
Topic.find({}).exec(function (err, topics) {
var i, topic_obj, topic_obj_list;
topic_obj_list = [];
if (err) { return next(err); }
for (i = 0; i < topics.length; i++) {
topic_obj = topics[i].toObject();
if (req.user.is_following) {
topic_obj.is_following = true;
} else {
topic_obj.is_following = false;
}
topic_obj_list.push(topic_obj);
}
return res.json(200, topic_obj_list);
});
P/S: I already tried simple solution like: topics[i].is_following = true, bit it didn't work.
You can shorten it to something like this:
Topic.find({}).exec(function (err, topics) {
if (err) { return next(err); }
return res.json(topics.map(function(topic) {
return topic.set(
'is_following',
req.user.is_following ? true : false,
{ strict : false }
);
}));
});
Explanation:
topics.map runs a function on each item of the topics array; the value that is returned from the function ends up in the result returned by map;
with topic.set(FIELD, VALUE, [{ strict : false }]) you can add/overwrite fields of a Mongoose document; when strict is false, the field doesn't have to exist in the schema;