
Security News
Feross on TBPN: How North Korea Hijacked Axios
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.
@firebase-graphql/graphql-codegen-firestore-rules
Advanced tools
@firebase-graphql/graphql-codegen-firestore-rulesfirebase-graphql package family.First, you need to define the structure of the firestore according to the GraphQL format.
# firestore.graphql
type User
@firestore(document: "/users/{id}")
@auth(
rules: [
{ allow: owner, ownerField: "id", operations: [create, update] }
{ allow: public, operations: [get, list] }
]
) {
id: ID!
name: String!
age: Int
}
type Post
@firestore(document: "/users/{userId}/posts/{id}")
@auth(
rules: [
{
allow: owner
ownerField: "userId"
operations: [create, update, delete]
}
{ allow: public, operations: [get, list] }
]
) {
id: ID!
userId: ID!
title: String!
content: String!
}
Then, you can generate the Firestore Rules file. Like this:
rules_version = "2"
service cloud.firestore {
match /databases/{database}/documents {
function isString(value) {
return value is string
}
function isInt(value) {
return value is int
}
function isBoolean(value) {
return value is bool
}
function isFloat(value) {
return value is float
}
function isID(value) {
return value is string
}
function isDate(value) {
return value is timestamp
}
function isMap(value) {
return value is map
}
function isRequired(source, field) {
return field in source && source[field] != null
}
function isNullable(source, field) {
return !(field in source) || source[field] == null
}
function isLoggedIn() {
return request.auth != null
}
function isAuthUserId(userId) {
return isLoggedIn() && request.auth.uid == userId
}
function isPost(value) {
return (
isMap(value) && value.keys().hasOnly(["__typename", "content", "title"])
&& isRequired(value, "__typename") && isString(value.__typename) && value.__typename == "Post"
&& isRequired(value, "content") && isString(value.content)
&& isRequired(value, "title") && isString(value.title)
)
}
function isUser(value) {
return (
isMap(value) && value.keys().hasOnly(["__typename", "age", "name"])
&& isRequired(value, "__typename") && isString(value.__typename) && value.__typename == "User"
&& (isNullable(value, "age") || isInt(value.age))
&& isRequired(value, "name") && isString(value.name)
)
}
match /users/{userId}/posts/{id} {
allow get: if (
true
)
allow list: if (
true
)
allow create: if (
isPost(request.resource.data)
&& isAuthUserId(userId)
)
allow update: if (
isPost(request.resource.data)
&& isAuthUserId(userId)
)
allow delete: if (
isAuthUserId(userId)
)
}
match /users/{id} {
allow get: if (
true
)
allow list: if (
true
)
allow create: if (
isUser(request.resource.data)
&& isAuthUserId(id)
)
allow update: if (
isUser(request.resource.data)
&& isAuthUserId(id)
)
}
}
}
yarn add -D @firebase-graphql/graphql-codegen-firestore-rules @graphql-codegen/cli graphql
# firestore.graphql
type User
@firestore(document: "/users/{id}")
@auth(
rules: [
{ allow: owner, ownerField: "id", operations: [create, update] }
{ allow: public, operations: [get, list] }
]
) {
id: ID!
name: String!
age: Int
}
# codegen.yml
generates:
firestore.rules:
schema: firestore.graphql
plugins:
- '@firebase-graphql/graphql-codegen-firestore-rules'
yarn graphql-codegen
this package generate validation functions for firestore.rules.
This package supports the following literals:
String → tha value should be a stringInt → tha value should be a intFloat → tha value should be a floatBoolean → tha value should be a boolID → tha value should be a stringDate → tha value should be a timestampYou can define enums in the schema.
# firestore.graphql
enum Category {
IT
MARKETING
EDUCATION
}
Then, this package generates validation functions for enums. like this:
# firestore.rules
function isCategory(value) {
return value is string && value in ["IT", "MARKETING", "EDUCATION"]
}
# firestore.graphql
type Image {
url: String!
width: Int!
height: Int!
}
type User {
id: ID!
name: String!
age: Int
profileImage: Image
}
type Post {
id: ID!
title: String!
content: String!
header: Image!
author: User!
}
Then,
# firestore.rules
function isImage(value) {
return (
isMap(value) && value.keys().hasOnly(["url", "width", "height"])
&& isRequired(value, "url") && isString(value.url)
&& isRequired(value, "width") && isInt(value.width)
&& isRequired(value, "height") && isInt(value.height)
)
}
functions isUser(value) {
return (
isMap(value) && value.keys().hasOnly(["id", "name", "age", "profileImage"])
&& isRequired(value, "id") && isID(value.id)
&& isRequired(value, "name") && isString(value.name)
&& (isNullable(value, "age") || isInt(value.age))
&& isRequired(value, "profileImage") && isImage(value.profileImage)
)
}
function isPost(value) {
return (
isMap(value) && value.keys().hasOnly(["id", "title", "content", "header", "author"])
&& isRequired(value, "id") && isID(value.id)
&& isRequired(value, "title") && isString(value.title)
&& isRequired(value, "content") && isString(value.content)
&& isRequired(value, "header") && isImage(value.header)
&& isRequired(value, "author") && isUser(value.author)
)
}
You can define Type with @firestore directive.
# firestore.graphql
type User @firestore(document: "/users/{id}") {
id: ID!
name: String!
age: Int
}
By doing this, you can generate a match expression for firestore.rules
# firestore.rules
match /users/{userId} {
}
This way the id field of the User will be treated as a special field and automatically understood to use the value from the path /users/{id}.
So, the validation for User will be as follows.
# firestore.rules
# Id is not included in the validation, since it is a special field obtained from the path.
function isUser(value) {
return (
isMap(value) && value.keys().hasOnly(["__typename", "age", "name"])
&& isRequired(value, "__typename") && isString(value.__typename) && value.__typename == "User"
&& (isNullable(value, "age") || isInt(value.age))
&& isRequired(value, "name") && isString(value.name)
)
}
It is recommended that the @firestore directive be used in conjunction with the @auth directive, described next.
The @firestore can be followed by an @auth directive to define access controls for that data.
Like this,
# firestore.graphql
type User
@firestore(document: "/users/{id}")
@auth(rules: [{ allow: public, operations: [get, list] }]) {
id: ID!
name: String!
age: Int
}
The @auth directive needs to be specified with a rules argument. These rules are calculated as a disjunction.
The format of the rule is as follows
| Field | Type | required | Description |
|---|---|---|---|
| allow | public, private, owner | :white_check_mark: | type of access control |
| operations | list of {get, list,create, update, delete} | :white_check_mark: | The operations to allow access to. |
| ownerField | string (but should be field name) | :negative_squared_cross_mark: (if allow: owner then :white_check_mark:) | Compare that field with the ID of the user accessing it. |
# firestore.graphql
type User
@firestore(document: "/users/{id}")
@auth(
rules: [{ allow: public, operations: [get, list, create, update, delete] }]
) {
id: ID!
name: String!
age: Int
}
# firestore.rules
match /users/{id} {
allow get: if (
true
)
allow list: if (
true
)
allow create: if (
isUser(request.resource.data)
&& true
)
allow update: if (
isUser(request.resource.data)
&& true
)
allow delete: if (
true
)
}
# firestore.graphql
type User
@firestore(document: "/users/{id}")
@auth(
rules: [{ allow: private, operations: [get, list, create, update, delete] }]
) {
id: ID!
name: String!
age: Int
}
# firestore.rules
match /users/{id} {
allow get: if (
isLoggedIn()
)
allow list: if (
isLoggedIn()
)
allow create: if (
isUser(request.resource.data)
&& isLoggedIn()
)
allow update: if (
isUser(request.resource.data)
&& isLoggedIn()
)
allow delete: if (
isLoggedIn()
)
}
# firestore.graphql
type User
@firestore(document: "/users/{id}")
@auth(
rules: [
{
allow: owner
operations: [get, list, create, update, delete]
ownerField: "id"
}
]
) {
id: ID!
name: String!
age: Int
}
# firestore.rules
match /users/{id} {
allow get: if (
isAuthUserId(id)
)
allow list: if (
isAuthUserId(id)
)
allow create: if (
isUser(request.resource.data)
&& isAuthUserId(id)
)
allow update: if (
isUser(request.resource.data)
&& isAuthUserId(id)
)
allow delete: if (
isAuthUserId(id)
)
}
If the ownerField is not path-based
# firestore.graphql
type User
@firestore(document: "/users/{id}")
@auth(
rules: [
{
allow: owner
operations: [get, list, create, update, delete]
ownerField: "userId"
}
]
) {
id: ID!
userId: ID!
name: String!
age: Int
}
# firestore.rules
match /users/{id} {
allow get: if (
isAuthUserId(resource.data.userId)
)
allow list: if (
isAuthUserId(resource.data.userId)
)
allow create: if (
isUser(request.resource.data)
&& isAuthUserId(request.resource.data.userId)
)
allow update: if (
isUser(request.resource.data)
&& (isAuthUserId(request.resource.data.userId) && isAuthUserId(resource.data.userId))
)
allow delete: if (
isAuthUserId(resource.data.userId)
)
}
You may want to match the value of a field with its creation or update time, such as createdAt or updatedAt
In such cases, the @createdAt and @updatedAt directives can be used.
# firestore.graphql
type User
@firestore(document: "/users/{id}")
@auth(
rules: [{ allow: private, operations: [get, list, create, update, delete] }]
) {
id: ID!
name: String!
age: Int
# The field name can be anything other than "createdAt" or "updatedAt".
createdAt: Date! @createdAt
updatedAt: Date! @updatedAt
}
And this will generate the following rules
# firestore.rules
match /users/{id} {
allow get: if (
isLoggedIn()
)
allow list: if (
isLoggedIn()
)
allow create: if (
isUser(request.resource.data)
&& request.resource.data.createdAt == request.time
&& request.resource.data.updatedAt == request.time
&& isLoggedIn()
)
allow update: if (
isUser(request.resource.data)
&& !("createdAt" in request.resource.data)
&& request.resource.data.updatedAt == request.time
&& isLoggedIn()
)
allow delete: if (
isLoggedIn()
)
}
FAQs
Unknown package
We found that @firebase-graphql/graphql-codegen-firestore-rules demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.

Security News
OpenSSF has issued a high-severity advisory warning open source developers of an active Slack-based campaign using impersonation to deliver malware.

Research
/Security News
Malicious packages published to npm, PyPI, Go Modules, crates.io, and Packagist impersonate developer tooling to fetch staged malware, steal credentials and wallets, and enable remote access.