Firebase security write rule of child based on user existence - firebase-security

Here is my security structure so far:
{
"rules":
{
"users":
{
"$user":
{
".read": true,
"Age":
{
".write": "$user === auth.uid",
".validate": "newData.isNumber()"
},
"Name":
{
".write": "$user === auth.uid",
".validate": "newData.isString()"
},
"friends":
{
"$friend":
{
"Age":
{
".write": "$user === auth.uid || $friend === auth.uid",
".validate": "newData.isString()"
},
"Name":
{
".write": "$user === auth.uid || $friend === auth.uid",
".validate": "newData.isNumber()"
}
}
}
}
}
}
}
Now, when I am trying to write to '$user' to Users, I have following error:
Attempt to write Success({"42":{"Age":42,"Name":"Nick","friends":{"11":{"Age":11,"Name":"Rob"}}}}) to /users with auth=Success({"id":42,"provider":"anonymous","uid":"anonymous:42"})
/
/users
No .write rule allowed the operation.
Write was denied.
When I set .write rule to users, then all write rules will be overwritten. I need to specify that all characteristics of $user can be written by $user only, but $friend can be written by $friend and $user. When I push users, I push them with friends, but then I will need the Friends to be able to change the their data at different users paths. Do you have any ideas?

Alright, so I played with rules little bit and decided to put write rules of child's into validation, and it works just great. Here is my final code:
{
"rules":
{
"users":
{
"$user":
{
".read": true,
".write": "$user === auth.uid",
"Age":
{
".validate": "newData.isNumber()"
},
"Name":
{
".validate": "newData.isString()"
},
"friends":
{
"$friend":
{
"Age":
{
".validate": "newData.isString() && ($user === auth.uid || $friend === auth.uid)"
},
"Name":
{
".validate": "newData.isNumber() && ($user === auth.uid || $friend === auth.uid)"
}
}
}
}
}
}
}

Related

Hide nested fields with "name" in $project mongodb

This is the document available that needs to be projected by hiding all the "name" fields in the document. Not sure if we have any specific way in mongo aggregation framework to search for all the nested fields with name - "name" and hide it. Please suggest
"group1":{
"field1":{
"name":"a"
},
"field2":{
"data":{
"name":"b"
}
},
"group2":{
"field2":{
"name":"a"
},
"field3":{
"data":{
"name":"b"
}
}
}
}
}
Expected output:
{
group1: {
field1: {
}, "field2": {
"data": {
}
},
"group2": {
"field2": {
}, "field3": {
"data": {
}
}
}
}
}

How to prevent to lost session after refresh in nuxt?

I am currently working on a nuxtJS app in which the session seems to be lost after any refresh (although only in dev, not while deployed). I've tried to look up in the auth module of nuxt, and have tried many answers on google, but nothing seems to work and I'm a bit lost.
nuxt.config.js
auth: {
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'token',
maxAge: 3600,
global: true,
},
refreshToken: {
property: 'refresh_token',
data: 'refresh_token',
maxAge: 60 * 60 * 24 * 30,
},
user: {
property: 'user',
},
endpoints: {
login: { url: '/authentication_token', method: 'post' },
refresh: { url: '/refresh/token', method: 'post' },
logout: false,
user: { url: '/api/user', method: 'get' },
},
autoLogout: true,
},
},
},
LoginMenu.js
methods: {
async onSubmit() {
try {
const response = await this.$auth.loginWith('local', {
data: this.login,
});
if (response.status === 200) {
await this.$auth.setUser({
email: this.login.email,
password: this.login.password,
});
await this.$router.push('/');
}
else {
this.loginFail();
}
}
catch (e) {
this.loginFail();
}
},
loginFail() {
this.showError = true;
},
},
nuxt auth.js
import Middleware from './middleware'
import { Auth, authMiddleware, ExpiredAuthSessionError } from '~auth/runtime'
// Active schemes
import { RefreshScheme } from '~auth/runtime'
Middleware.auth = authMiddleware
export default function (ctx, inject) {
// Options
const options = {
"resetOnError": false,
"ignoreExceptions": false,
"scopeKey": "scope",
"rewriteRedirects": true,
"fullPathRedirect": false,
"watchLoggedIn": true,
"redirect": {
"login": "/login",
"logout": "/",
"home": "/",
"callback": "/login"
},
"vuex": {
"namespace": "auth"
},
"cookie": {
"prefix": "auth.",
"options": {
"path": "/"
}
},
"localStorage": {
"prefix": "auth."
},
"defaultStrategy": "local"
}
// Create a new Auth instance
const $auth = new Auth(ctx, options)
// Register strategies
// local
$auth.registerStrategy('local', new RefreshScheme($auth, {
"token": {
"property": "token",
"maxAge": 3600,
"global": true
},
"refreshToken": {
"property": "refresh_token",
"data": "refresh_token",
"maxAge": 2592000
},
"user": {
"property": "user"
},
"endpoints": {
"login": {
"url": "/authentication_token",
"method": "post"
},
"refresh": {
"url": "/refresh/token",
"method": "post"
},
"logout": false,
"user": {
"url": "/api/user",
"method": "get"
}
},
"autoLogout": true,
"name": "local"
}))
// Inject it to nuxt context as $auth
inject('auth', $auth)
ctx.$auth = $auth
// Initialize auth
return $auth.init().catch(error => {
if (process.client) {
// Don't console log expired auth session errors. This error is common, and expected to happen.
// The error happens whenever the user does an ssr request (reload/initial navigation) with an expired refresh
// token. We don't want to log this as an error.
if (error instanceof ExpiredAuthSessionError) {
return
}
console.error('[ERROR] [AUTH]', error)
}
})
}

How to get the correct object in an nested array in Vue.js?

I use Axios to display a JSON data and I have succeeded. But I want to show an object based on date and time, it shows now all data and I need to filter it.
So I want to look at today's date and show the object based on that, so I want to show the next upcoming event. (24/05/2020)
What I currently have:
Json:
{
"doc": [
{
"data": {
"events": {
"18807612": {
"_dt": {
"_doc": "time",
"time": "18:45",
"date": "14/05/20",
"tz": "UTC",
"tzoffset": 0,
"uts": 1566067500
},
"week": 33,
"teams": {
"home": {
"name": "name 1",
"mediumname": "name1",
"uid": 3014
},
"away": {
"name": "name 2",
"mediumname": "name 2",
"uid": 3020
}
}
},
"18807618": {
"_dt": {
"_doc": "time",
"time": "18:45",
"date": "24/05/20",
"tz": "UTC",
"tzoffset": 0,
"uts": 1566067500
},
"week": 33,
"teams": {
"home": {
"name": "name 1",
"mediumname": "name1",
"uid": 3014
},
"away": {
"name": "name 2",
"mediumname": "name2",
"uid": 3020
}
}
}
}
}
}
]
}
Store:
async loadPosts({ commit }) {
// Define urls pages
const urlEvents = 'http://api.example.com/302020';
// Set pages
const [
responseEvents
] = await Promise.all([
// Responses pages
this.$axios.get(urlEvents)
]);
// variables pages
this.events = responseEvents.data.doc[0].data.events
// mutations pages
commit('SET_EVENTS', this.events)
}
},
mutations: {
SET_EVENTS (state, events) {
state.events = events;
}
}
And to show the data I use this:
import {mapState} from 'vuex';
export default {
name: 'NextMatch',
mounted() {
this.$store.dispatch('loadPosts')
},
computed: {
...mapState([
'events'
])
}
}
<h1>{{events}}</h1>
But this shows all data, and what I try to get is the first upcoming event for the object with the "uid": 3014.
So I want to show the date, time and names of the home and away team.
How can I get the correct data by filtering the data?
Something like this or similar to this should work:
In your Vue component's <template>:
`<h1>{{selectedEvent._dt.date}}</h1>`
In your Vue component's <script>:
props: {
eventID: {
type: Number,
default: 3014
},
},
computed: {
...mapState([
'events'
]),
eventsArr(){
if (!this.events) return {} //make sure Object.entries gets object.
return Object.entries(this.events)
},
selectedEvent(){
const selectedArr = this.eventsArr.find(([eID, e]) => e.teams.home.uid === this.eventID)
return selectedArr[1]
}
}

Vue Change state in forEach loop and if condition to update replies of any comment

I have a State with editedIndex i want to change it in forEach loop but i am not able to call it in that loop.
i have done this code so far
data() {
return {
dialog: false,
comments: [],
editedReply: {
reply: null,
comment_id: null,
name: JSON.parse(localStorage.getItem("user")).name,
email: JSON.parse(localStorage.getItem("user")).email
},
editedIndex: -1
};
},
in above code i have added the initial state of comments which contains index of all comments
I am trying to update the replies of each comment.
handleEdit(reply) {
let commentArray = this.comments;
commentArray.forEach(function(comment) {
comment.reply.forEach(function(item) {
if (reply.id === item.id) {
this.editedIndex = comment.reply.indexOf(item);
this.editedReply = Object.assign({}, item);
}
});
});
this.dialog = true;
},
from i have the list of comments in this.comments and reply represents the reply on which i have clicked to update.
my problem here is i am not able to call this.editedIndex and this.editedReply in if condition as i have mentioned above.
I have used comment.reply every comment contains a array of reply which you can see in below json data for comment i want to update the this json reply
json data for my comments is
{
"comments": [
{
"id": 5,
"comment": "nice blog",
"name": "test user",
"email": "dhruvil#gkmit.co",
"status": true,
"created_at": "2020-05-28T04:36:46.797Z",
"article": {
"id": 308,
"title": "test for comment article"
},
"reply": [
{
"id": 99,
"reply": "abcbc",
"name": "test2",
"email": "test2#mailinator.com",
"created_at": "2020-05-29T13:23:31.358Z"
},
{
"id": 100,
"reply": "abcbc",
"name": "test2",
"email": "test2#mailinator.com",
"created_at": "2020-05-29T13:23:31.521Z"
},
]
},
{
.......... and so on
},
]
}
Try using this snippet for handleEdit method:
handleEdit(reply) {
let commentArray = this.comments;
commentArray.forEach(comment => {
comment.reply.forEach(item => {
if (reply.id === item.id) {
this.editedIndex = comment.reply.indexOf(item);
this.editedReply = Object.assign({}, item);
}
});
});
this.dialog = true;
},
What's different here is I used arrow functions for the callbacks of forEach operations.

Vuejs2: Vue Tables 2 - Multiple Custom filters

I'm trying to use a Vue table 2 filter to filter data by date, unfortunately it is not wroking and I am not able to find the reason. Has anyone tried such multiple filters with Vue table 2?
I went through the documentation but cannot find a solution.
https://matanya.gitbook.io/vue-tables-2/custom-filters
Html code to filter the data by date
<div class="col-md-4">
<div class="form-group">
<label for="sel1">Start Date:</label>
<input type="text" class="form-control" #keyup="applyFilterSearchText(searchText)" v-model="searchText" placeholder="End date" />
</div>
</div>
import { Event } from "vue-tables-2";
import axios from "axios";
export default {
title: "HelloWorld",
props: {
msg: String
},
data() {
return {
letters: ["Filled", "Unfilled", "Expired"],
selectedLetter: "",
searchText: "",
columns: ["refNumber", "vacancyTitle", "sector", "startDate", "endDate", "vacancyStatus"],
//data: getdetails(),
options: {
headings: {
refNumber: "Ref",
vacancyTitle: "Title",
sector: "Sector",
startDate: "Start",
endDate: "End",
vacancyStatus: "Status"
},
customFilters: [
{
name: "alphabet",
callback: function(row, query) {
return row.vacancyStatus == query;
}
},
{
name: "datefilter",
callback: function(row, query) {
return row.startDate == query;
}
}
],
// filterAlgorithm: {
// textsearch(row, query) {
// return (row.title).includes(query);
// }
// },
sortable: ["startDate", "vacancyTitle","endDate"],
sortIcon: {
base: "fa",
is: "fa-sort",
up: "fa-sort-asc",
down: "fa-sort-desc"
},
texts: {
filter: "Search by text:"
}
},
tableData:[],
};
},
methods: {
applyFilter(event) {
this.selectedLetter = event.target.value;
Event.$emit("vue-tables.filter::alphabet", this.selectedLetter);
},
applyFilterSearchText() {
console.log(this.searchText,"heiiiiiiiiiiii");
Event.$emit("vue-tables.filter::datefilter", this.searchText);
},
getdetails(){
axios.get("https://localhost:44399/api/Vacancy")
.then((res) => {
console.log(res.data,"ressssssss");
this.tableData = res.data;
})
.catch(function(error) {
console.log("Error: ", error);
});
}
},
mounted() {
this.getdetails();
}
};
A potential solution to that is to sort the data before using it in your data-table. Start by creating a computed of your data but with all your potential filters in it and create data variables with "parameters" (sort direction, sort column...)
export default {
title: "HelloWorld",
props: {
msg: String
},
data () {
return {
yourData: [],
sortBy: 'name',
sortDir: 'asc',
filterSearch: ''
}
},
computed: {
filteredData () {
if (filterSearch != '') {
let _this = this;
return this.sortedData.filter(item => {
return item.name.toLowerCase().includes(_this.filterSearch.toLowerCase());
})
} else {
return this.sortedData;
}
},
sortedData() {
return this.yourData.sort((a, b) => {
let modifier = 1;
if (this.sortBy == "order") {
if (this.sortDir === 'asc') {
return a[this.sortBy] - b[this.sortBy]
} else if (this.sortDir === 'desc') {
return b[this.sortBy] - a[this.sortBy]
}
} else {
if (this.sortDir === 'desc') modifier = -1;
if (a[this.sortBy] < b[this.sortBy]) return -1 * modifier;
if (a[this.sortBy] > b[this.sortBy]) return modifier;
return 0;
}
});
}
}
}
With that you just have to replace the props value you use to pass data to your VueTables