firebase rules: does user have right to see document - firebase-authentication

I am trying to write some rules to allow users to access only the documents they have the rights to.
I have two collections: a "travels" and a "users" collection.
The "travels" collection has several travels (documents) with names "001", "002", "003", ...
The users collection has users (documents) with names "user1#mail.com", "user2#mail.com",...
Inside each user there is an Object (map) called "allowedTravels", in which i keep track of which travels that user can see. Something like this:
travels: {
001: {
name: 'Nice travel'
},
002: {
name: 'Amazing Trip'
}
}
users: {
user1#email.com: {
allowedTravels: {
001: {
hasPayed: true
}
}
},
user2#mail.com: {
allowedTravels: {
001: {
hasPayed: false
},
002: {
hasPayed: true
}
}
}
}
What i want is to allow users to access the travel documents only if they have access to them, in this case user1 should have access to travel 001, and user2 should have access to travel 001 and 002.
What i want to check is if inside the users document, in the allowedTravels object there is a property with the name of the "travel document". If so: allow, if not: deny
At the moment my rules look like this:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if isSignedIn();
}
}
function isSignedIn() {
return request.auth.uid != null;
}
}
What i have tried was something like this:
match /{document} {
return exists(/users/${request.auth.email}/allowedTravels/{document})
}
What would be the correct way to achieve what i am looking for?
I appreciate any help you can give me. thanks!

Related

How to create a follow/followed relationship using Neo4j and Neo4j GraphQL Library with #auth?

Using the following schema:
type Profile {
id: ID! #id
username: String! #unique(constraintName: "unique_email")
follows: [Profile!]!
#relationship(
type: "FOLLOWS"
properties: "BaseRelationship"
direction: OUT
)
followers: [Profile!]!
#relationship(
type: "FOLLOWS"
properties: "BaseRelationship"
direction: IN
)
}
And extending it to use the #auth directive:
extend type Profile
#auth(
rules: [
{ operations: [CREATE, UPDATE, DELETE, UPDATE, CONNECT, DISCONNECT], allow: { username: "$jwt.name" } }
{ operations: [READ], isAuthenticated: true }
]
)
I am only getting forbidden when I try the following mutation (jwt.name is user1):
mutation UpdateProfiles {
updateProfiles(
where: { username: "user1" }
update: {
follows: [{ connect: [{ where: { node: { username: "user2" } } }] }]
}
) {
info {
relationshipsCreated
}
}
}
Just want to make user1 follow user2 and vice versa. Tried changing allow to bind and to where and variations of the mutation but I can't get it to work.
If I use the same mutation but make both arguments user1, then user1 is able to follow himself, so I assume there is something wrong with not being able to allow the incoming connection to user2.
But how can I allow that the authorized user can follow someone else?

what is the proper way to get my google account profile image (URL) in NodeJS

see below error message and source code, doesn't work even after I added person fields of photos:
TypeError: Cannot read properties of undefined (reading 'url')
var p = google.people("v1");
p.people.get(
{
resourceName: "people/me",
personFields: "names,emailAddresses,photos",
auth: oauth2Client,
},
function (err, user) {
if (err) { return; }
res.json({
name: encoder.htmlEncode(user.displayName),
picture: user.image.url,
});
}
);
You should have a look into the docs. The people.get request returns a Person object. And such a Person does not have an image property, so you cant't access user.image.url because user.image does not exist. Neither does user.displayName, btw.
What a Person actually looks like is as follows (the ... meaning there are additional properties too, look up in the docs, if you need more)
{
...
coverPhotos: [{url: "https://url.to/image", ...}],
...
names: [{ displayName: "John Doe", ...}],
...
}
So to get the name and picture, first of all, instead of photos you need to request coverPhotos. Then you can extract the desired values, as follow:
p.people.get(
{
resourceName: "people/me",
personFields: "names,emailAddresses,coverPhotos",
auth: oauth2Client,
},
function (err, user) {
if (err) { return; }
let
name = user.names?.[0]?.displayName || "John Doe",
url = user.coverPhotos?.[0]?.url
res.json({
name: encoder.htmlEncode(name),
picture: user.image.url,
});
});
I used the conditional chaining ?. here, to make sure, this code does not run into an exception if for instance coverPhotos does not exist or is an empty array.

GraphQL Resolver for Nested Array of Objects

I am trying to get to grips with the GraphQL schema language as part of a work project. I'm running into problems I think because I'm not sure how to write the resolver for a particular data structure I need to use. I have some data for an appointment management system I am writing. There are at this point three collections - Staff, Account, and Booking. A simplified version of the typical json data looks like this:
Staff: {
id: 0,
Name: 'Joe Blogs',
Speciality: 'Fitter'
}
Account: {
id: 0,
Name: 'Fred Foo',
Company: 'Acme Holdings',
staffId: 0
}
Booking: {
id: 0,
Date: '2018-03-23',
staffId: 0,
accountId: 0,
AssignedStaff: [
{id: 0, staffId: 1},
{id: 1, staffId: 3}
]
}
So, a booking will relate to a particular account and be owned by a particular staff member. It will also have an arbitrary number of other staff assigned to it. My GraphQL schema looks like this:
type Staff {
id: Int!
Name: String!
Speciality: String!
accounts: [Account]
bookings: [Booking]
}
type Account {
id: Int!
Name: String!
Company: String!
staff: Staff!
bookings: [Booking]
}
type Booking {
id: Int!
Date: String!
staff: Staff!
account: Account!
AssignedStaff: [AssignedStaff]
}
type AssignedStaff {
id: Int!
staff: Staff!
}
I have working resolvers for the relationships between Staff and Account and Booking working properly. Where I am having problems is with writing a resolver for the assigned staff on a booking. I am doing the development using static dummy data for the time being. The working resolver functions look like this:
Account: {
bookings (account) {
return booking.filter(booking => booking.accountId === account.id)
},
staff (account) {
return staff.find(staff => staff.id === account.staffId)
}
},
Booking: {
account (booking) {
return account.find(account => account.id === booking.accountId)
},
staff (booking) {
return staff.find(staff => staff.id === booking.staffId)
}
},
Staff: {
accounts (staff) {
return account.filter(account => account.staffId === staff.id)
},
bookings (staff) {
return booking.filter(booking => booking.staffId === staff.id)
}
}
and they work fine. I can do e.g. a query like this:
staff(id: 0){
Name
accounts {
Name
bookings {
Date
}
}
}
and it works, the data returned is exactly what I expect. The problem arises when I try to return data about the assigned staff on a booking. I have a resolver for AssignedStaff which currently looks like this:
AssignedPhotographer: {
staff(booking) {
return staff.filter(staff => staff.id === booking.AssignedStaff.staffId)
}
}
but when I run a query against it like this for instance:
staff(id: 0){
Name
accounts {
Name
bookings {
Date
AssignedStaff {
staff{
Name
}
}
}
}
}
The data I get back has an array of null values for AssignedStaff. The number of nulls matches the number of assigned staff for the booking, but it seemingly is not linking to the Staff type properly. If I just request the ids of the assigned staff for a booking like this:
staff(id: 0){
Name
accounts {
Name
bookings {
Date
AssignedStaff {
id
}
}
}
}
It works ok and gives me back the correct data. I'm guessing that the problem is with the way I have done my resolvers, probably specifically with the AssignedStaff resolver. Can anybody please tell me what I'm doing wrong?
You have any array of Staff objects that you filter and then try to return as an array of AssignedStaff. Staff and AssignedStaff do not share any fields except for id -- which is why you see the id field populated but not the staff field.
GraphQL is expecting an array like this:
[ { id, staff } ]
and you are passing it
[ { id, name, speciality } ]
You'll need to modify your resolver to look something like this:
return staff
.filter(s => s.id === booking.AssignedStaff.staffId)
.map(f => ({ id: f.id, staff: f }))
I don't know what (if any) the intended difference between AssignedStaff.id and AssignedStaff.staff.id is so you may need to fiddle with the above code but it should give you a starting point.

Validation of fetched data from API Redux React

So, I will go straight to the point. I am getting such data from api:
[
{
id: 123,
email: asd#asd.com
},
{
id: 456,
email: asdasd.com
},
{
id: 789,
email: asd#asd
},
...
]
and I should validate email and show this all info in a list, something like this:
asd#asd.com - valid
asdasd.com - invalid
asd#asd - invalid
...
My question is what is the best way to store validation data in a store? Is it better to have something like "isValid" property by each email? I mean like this:
store = {
emailsById: [
123: {
value: asd#asd.com,
isValid: true
},
456: {
value: asdasd.com,
isValid: false
},
789: {
value: asd#asd,
isValid: false
}
...
]
}
or something like this:
store = {
emailsById: [
123: {
value: asd#asd.com
},
456: {
value: asdasd.com
},
789: {
value: asd#asd
}
...
],
inValidIds: ['456', '789']
}
which one is better? Or maybe there is some another better way to have such data in store? Have in mind that there can be thousands emails in a list :)
Thanks in advance for the answers ;)
I recommend reading the article "Avoiding Accidental Complexity When Structuring Your App State" by Tal Kol which answers exactly your problem: https://hackernoon.com/avoiding-accidental-complexity-when-structuring-your-app-state-6e6d22ad5e2a
Your example is quite simplistic and everything really depends on your needs but personally I would go with something like this (based on linked article):
var store = {
emailsById: {
123: {
value: '123#example.com',
},
456: {
value: '456#example.com',
},
789: {
value: '789#example.com',
},
// ...
},
validEmailsMap: {
456: true, // true when valid
789: false, // false when invalid
},
};
So your best option would be to create a separate file that will contain all your validations methods. Import that into the component you're using and then when you want to use the logic for valid/invalid.
If its something that you feel you want to put in the store from the beginning and the data will never be in a transient state you could parse your DTO through an array map in your reducer when you get the response from your API.
export default function (state = initialState, action) {
const {type, response} = action
switch (type) {
case DATA_RECIEVED_SUCCESS:
const items = []
for (var i = 0; i < response.emailsById.length; i++) {
var email = response.emailsById[i];
email.isValid = checkEmailValid(email)
items.push(email)
}
return {
...state,
items
}
}
}
However my preference would be to always check at the last moment you need to. It makes it a safer design in case you find you need to change you design in the future. Also separating the validation logic out will make it more testable
First of all, the way you defined an array in javascript is wrong.
What you need is an array of objects like,
emails : [
{
id: '1',
email: 'abc#abc.com',
isValid: true
},
{
id: '2',
email: 'abc.com',
isValid: false;
}
];
if you need do access email based on an id, you can add an id property along with email and isValid. uuid is a good way to go about it.
In conclusion, it depends upon your use case.
I believe, the above example is a good way to keep data in store because it's simple.
What you described in your second example is like maintaining two different states. I would not recommend that.

Redux - Filterable category with products - Actions & Filter

My state looks exactly like this:
{
categories: {
"unique-category-id" {
"data": {
// All kind of data (name, description ,etc )
"products": [
{
// Products that belong to this category with the current filter
}
]
},
"readyState": "CATEGORY_FETCHED",
"query": { // This object holds all the params that the filter allows to choose from
"brands": [],
"options": {
"usb": true
"minPrice": 200
}
}
}
}
}
This works and fetches data correctly. Now it's time to implement the filtering funcionality. I am trying to make it work like this, not sure if this is the "redux" way of doing things.
1.- On each filter on the category page we assign a click handler:
<li onClick={this.toggleFilterField} key={item.VALUE}>{item.NAME}</li>
toggleFilterField is passed into the container via mapDispatchToProps:
const mapDispatchToProps = (dispatch) => {
return {
toggleFilterField: (category, filter) => {
dispatch(toggleFilterField(category, filter))
}
}
}
export { CustomTagFilter };
export default connect(null, mapDispatchToProps)(CustomTagFilter);
2.- My toogleFilterField should just return an action like this one:
return {
type: CHANGE_FILTER,
category,
filter
}
Then my category_reducer.js should handle this action and update the following state key
state.categories[unique-category-id].query
Now this is OK, but now, after applying the filter to the state I would have to refetch the data from the category.
How and where do I fire a new action based on a previous action success?
Is this the correct way of handling filtered elements in redux that come from a paginated API?