Issue with Permissions for Google Cloud Functions - firebase

When one of my firebase cloud functions is triggered (cloud firestore trigger), I get a permissions error. I am unsure how to resolve this issue and there are few relevant resources. I have included the function itself as well as the error below.
I have tried reinitializing the app, disabling and reenabling the api, and deleting and redeploying the functions.
Function:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import {reportError} from "../logging";
import {chargeTypes} from "../constants/constants";
import {handleCreateTeam} from "./create-team";
import {handleJoinTeam} from "./join-team";
import {handleAcceptInvite} from "./accept-invite";
export async function handleNewJoinTeamDocument(event:
admin.firestore.DocumentSnapshot, context: functions.EventContext, db:
admin.firestore.Firestore) {
const todo = event.data();
if (todo === undefined) {
return reportError("Todo returned no data in handle new join team document", {user: context.params.id});
}
if (todo.processed) {
return {message: "Already processed this queue item"}
}
let result;
switch (todo.type) {
case chargeTypes.ACCEPT_INVITE:
result = handleAcceptInvite(todo, event, context, db);
break;
case chargeTypes.CREATE_TEAM:
result = handleCreateTeam(todo, event, context, db);
break;
case chargeTypes.JOIN_TEAM:
result = handleJoinTeam(todo, event, context, db);
break;
default:
break
}
return await result;
}
Error:
Error: 7 PERMISSION_DENIED: The caller does not have permission at
Object.exports.createStatusError
(/srv/node_modules/grpc/src/common.js:91:15) at
Object.onReceiveStatus
(/srv/node_modules/grpc/src/client_interceptors.js:1204:28) at
InterceptingListener._callNext
(/srv/node_modules/grpc/src/client_interceptors.js:568:42) at
InterceptingListener.onReceiveStatus
(/srv/node_modules/grpc/src/client_interceptors.js:618:8) at
callback
(/srv/node_modules/grpc/src/client_interceptors.js:845:24)
Log Details:
{
insertId: "000000-b7bc9521-25b8-4357-9301-a5c1df269ef4"
labels: {
execution_id: "767010698187131"
}
logName: "projects/snowballtesting-d70da/logs/cloudfunctions.googleapis.com%2Fcloud-functions"
receiveTimestamp: "2019-09-29T16:38:47.207554787Z"
resource: {
labels: {…}
type: "cloud_function"
}
severity: "ERROR"
textPayload: "Error: 7 PERMISSION_DENIED: The caller does not have permission
at Object.exports.createStatusError (/srv/node_modules/grpc/src/common.js:91:15)
at Object.onReceiveStatus (/srv/node_modules/grpc/src/client_interceptors.js:1204:28)
at InterceptingListener._callNext (/srv/node_modules/grpc/src/client_interceptors.js:568:42)
at InterceptingListener.onReceiveStatus (/srv/node_modules/grpc/src/client_interceptors.js:618:8)
at callback (/srv/node_modules/grpc/src/client_interceptors.js:845:24)"
timestamp: "2019-09-29T16:38:45.946Z"
trace: "projects/snowballtesting-d70da/traces/daf59e0d15388a1c4500bb4a88a7a084"
}

Related

What is the best practice to bypass my specific dynamic code evaluation in next.js middleware?

I use next.js middleware to retrieve a data stored inside a cookie, and to check in a db (using strapi) if this specific user exists, or if he needs to register before going further.
// middleware.js
import { getToken } from 'next-auth/jwt';
import qs from 'qs';
import { MY_DB } from './constants';
export async function middleware(request) {
const token = await getToken({
req: request,
secret: process.env.SECRET,
});
const params = qs.stringify({
filters: {
address: {
$eq: token.sub,
},
},
});
const url = MY_DB + '/api/users/?' + params;
const result = await fetch(url, {
method: 'GET',
headers: { accept: 'application/json' },
});
// remaining code checks if the request is empty or not and returns the appropriate page
(...)
building my project returns the following error :
Failed to compile.
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/implementation.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation
Import trace for requested module:
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/implementation.js
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/index.js
./node_modules/.pnpm/get-intrinsic#1.1.3/node_modules/get-intrinsic/index.js
./node_modules/.pnpm/side-channel#1.0.4/node_modules/side-channel/index.js
./node_modules/.pnpm/qs#6.11.0/node_modules/qs/lib/stringify.js
./node_modules/.pnpm/qs#6.11.0/node_modules/qs/lib/index.js
> Build failed because of webpack errors
 ELIFECYCLE  Command failed with exit code 1.
I highly suspect the qs.stringify call given the stacktrace, but how can I overcome this in an elegant way ?

Prisma on production - User 'xxx' has exceeded the 'max_user_connections' resource

I'm having an issue when I upload my Next.js app in production (in Vercel). When I run the app in development, it works fine. Only 1 connection is created. But when I use the app in production, instantly reaches the max users connections (5).
I don't know what to share exactly, but this is my client.js:
import { PrismaClient } from "./generators/app";
export const prisma =
global.prisma ||
new PrismaClient();
if (process.env.NODE_ENV !== 'production') global.prisma = prisma;
And this is how I import it from api files:
import { prisma } from "../../../prisma/client";
I've tried both guides:
https://www.prisma.io/docs/guides/performance-and-optimization/connection-management
https://www.prisma.io/docs/guides/database/troubleshooting-orm/help-articles/nextjs-prisma-client-dev-practices
This is the error:
2022-10-27T20:58:32.492Z 07594f4a-727a-4e98-a4aa-264d060dc08b ERROR PrismaClientInitializationError:
Invalid `prisma.user.findUnique()` invocation:
Error querying the database: Server error: `ERROR 42000 (1226): User 'xxx' has exceeded the 'max_user_connections' resource (current value: 5)'
at RequestHandler.handleRequestError (/var/task/.next/server/chunks/7738.js:31215:19)
at RequestHandler.request (/var/task/.next/server/chunks/7738.js:31188:18)
at async PrismaClient._request (/var/task/.next/server/chunks/7738.js:32176:24)
at async havePermission (/var/task/.next/server/chunks/3433.js:49:40)
at async getServerData (/var/task/.next/server/pages/api/app/user/get/[column].js:181:34)
at async Object.apiResolver (/var/task/node_modules/next/dist/server/api-utils/node.js:366:9)
at async NextNodeServer.runApi (/var/task/node_modules/next/dist/server/next-server.js:469:9)
at async Object.fn (/var/task/node_modules/next/dist/server/next-server.js:719:37)
at async Router.execute (/var/task/node_modules/next/dist/server/router.js:247:36)
at async NextNodeServer.run (/var/task/node_modules/next/dist/server/base-server.js:346:29) {
clientVersion: '4.3.1',
errorCode: undefined
}
2022-10-27T20:58:32.501Z 07594f4a-727a-4e98-a4aa-260d060dc08b ERROR PrismaClientInitializationError:
Invalid `prisma.user.findUnique()` invocation:
Error querying the database: Server error: `ERROR 42000 (1226): User 'xxx' has exceeded the 'max_user_connections' resource (current value: 5)'
at RequestHandler.handleRequestError (/var/task/.next/server/chunks/7738.js:31215:19)
at RequestHandler.request (/var/task/.next/server/chunks/7738.js:31188:18)
at async PrismaClient._request (/var/task/.next/server/chunks/7738.js:32176:24)
at async havePermission (/var/task/.next/server/chunks/3433.js:49:40)
at async getServerData (/var/task/.next/server/pages/api/app/user/get/[column].js:181:34)
at async Object.apiResolver (/var/task/node_modules/next/dist/server/api-utils/node.js:366:9)
at async NextNodeServer.runApi (/var/task/node_modules/next/dist/server/next-server.js:469:9)
at async Object.fn (/var/task/node_modules/next/dist/server/next-server.js:719:37)
at async Router.execute (/var/task/node_modules/next/dist/server/router.js:247:36)
at async NextNodeServer.run (/var/task/node_modules/next/dist/server/base-server.js:346:29) {
clientVersion: '4.3.1',
errorCode: undefined
}
RequestId: 07594f4a-727a-4e98-a4aa-264d060dc08b Error: Runtime exited with error: exit status 1
Runtime.ExitError
After that it tries every second to make a GET request to the api with 500 response.
Vercel by default creates like 5 new connections to the database (maybe for the CDNs or something like that) and you need a larger connection limit.

ionic capacitor-community/sqlite problems

Ionic 6 app using capacitor-community/sqlite#3.4.2-3.
Creating connection with
await CapacitorSQLite.createConnection({database:DBNAME,version:DB_VERSION,encrypted:false,mode:"secret"});
I get the following error:
"While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length."
Using 3.4.0 version with same code, the error is:
"Error: Query: Attempt to invoke virtual method 'com.getcapacitor.JSArray com.getcapacitor.community.database.sqlite.CapacitorSQLite.query(java.lang.String, java.lang.String, com.getcapacitor.JSArray)' on a null object reference"
any ideas?
thanks
I am facing 2 million issues but I think you have put a superfluous curly bracket {} in your constructor call and you are calling the object directly.
const db = await this.sqlite.createConnection(this.dbname, true, 'encryption', 1, false); :
where this.sqlite is initiated in the constructor to a service (angular) with a call to initializePlugin
initializePlugin(): Promise<boolean> {
return new Promise(resolve => {
this.platform = Capacitor.getPlatform();
if (this.platform === 'ios' || this.platform === 'android') {
this.native = true;
}
this.sqlite = new SQLiteConnection(CapacitorSQLite);
resolve(true);
});
}
You may also need the following in your import statement:
import { Injectable } from '#angular/core';
import { Capacitor } from '#capacitor/core';
import {
CapacitorSQLite, SQLiteConnection,
capEchoResult
} from '#capacitor-community/sqlite';
import { Platform } from '#ionic/angular';
At least, it works for me.

Firestore update on server only

When retrieving data from Firestore one has the option of forcing retrieval from the server. The default option is cache and server, as determined by Firestore.
I have a certain usage where a command and control node is issuing real-time commands to remote nodes backed by Firestore. This requires the updates to be done on the server (or fail) so that the C&C node has certainty on the execution (or failure) in real-time. What I would like to do is to disable use of cache with these updates. I have not found a way to do that. Is this possible with current capabilities of Firestore?
Note that it is not desirable to disable Firestore caching at a global level as the cache is beneficial in other situations.
----EDIT-----
Based on the responses I have created this update method that attempts to force updating the server using a transaction.
A couple of notes:
This is dart code.
Utils.xyz is an internal library and in this case it is being used to log.
I have reduced the network speed for the test to simulate a bad network connection.
The timeout is set to 5 seconds.
Here is the output of my log:
I/flutter (22601): [2021-06-06 22:35:30] [LogLevel.DEBUG] [FirestoreModel] [update] [We are here!]
I/flutter (22601): [2021-06-06 22:35:47] [LogLevel.DEBUG] [FirestoreModel] [update] [We are here!]
I/flutter (22601): [2021-06-06 22:36:02] [LogLevel.DEBUG] [FirestoreModel] [update] [We are here!]
I/flutter (22601): [2021-06-06 22:37:18] [LogLevel.DEBUG] [FirestoreModel] [update] [We are here!]
I/flutter (22601): [2021-06-06 22:37:20] [LogLevel.INFO] [FirestoreModel] [update] [Transaction successful in 110929ms.]
Firebase completely ignores the timeout of 5 seconds; tries to update 4 times each time ~15 seconds apart and is finally successful after 110 seconds. I am after a real-time response within seconds (5 sec) or failure.
Future<void> update(
Map<String, dynamic> data, {
WriteBatch batch,
Transaction transaction,
bool forceServer = false,
}) async {
// If updating there must be an id.
assert(this.id != null);
// Only one of batch or transaction can be non-null.
assert(batch == null || transaction == null);
// When forcing to update on server no transaction or batch is allowed.
assert(!forceServer || (batch == null && transaction == null));
try {
if (forceServer) {
DateTime start = DateTime.now();
await FirebaseFirestore.instance.runTransaction(
(transaction) async {
await update(data, transaction: transaction);
Utils.logDebug('We are here!');
},
timeout: Duration(seconds: 5),
);
Utils.logDebug('Transaction successful in ${DateTime.now().difference(start).inMilliseconds}ms.');
} else {
DocumentReference ref =
FirebaseFirestore.instance.collection(collection).doc(this.id);
if (batch != null)
batch.update(ref, data);
else if (transaction != null)
transaction.update(ref, data);
else
await ref.update(data);
}
} catch (e, s) {
Utils.logException('Error updating document $id in $collection.', e, s);
// Propagate the error.
rethrow;
}
}
This requires the updates to be done on the server (or fail)
For that you could use Transactions and batched writes.
Transactions will fail when the client is offline.
Check out doc
To get live data from the server once, you would use:
firebase.firestore()
.doc("somecollection/docId")
.get({ source: "server" })
.then((snapshot) => {
// if here, snapshot.data() is from the server
// TODO: do something with data
})
.catch((err) => {
// if here, get() encountered an error (insufficient permissions, server not available, etc)
// TODO: handle the error
});
To get realtime live data from only the server (ignoring the cache), you would use:
const unsubscribe = firebase.firestore()
.doc("somecollection/docId")
.onSnapshot({ includeMetadataChanges: true }, {
next(snapshot) {
// ignore cache data
if (snapshot.metadata.fromCache) return;
// if here, snapshot.data() is from the server
// TODO: do something with data
},
error(err) {
// if here, onSnapshot() encountered an error (insufficient permissions, etc)
// TODO: handle the error
}
});
To write to the server, you would use the normal write operations - delete(), set(), and update(); as they all return Promises that will not resolve while the client is offline. If they have resolved, the data stored on the server has been updated.
To test if you are online or not, you can try and pull a non existant document down from the server like so:
/**
* Attempts to fetch the non-existant document `/.info/connected` to determine
* if a connection to the server is available.
* #return {Promise<boolean>} promise that resolves to a boolean indicating
* whether a server connection is available
*/
function isCurrentlyOnline() {
// unlike RTDB, this data doesn't exist and has no function
// must be made readable in security rules
return firebase.firestore()
.doc(".info/connected")
.get({ source: "server" })
.then(
() => {
// read data successfully, we must be online
return true;
}, (err) => {
// failed to read data, if code is unavailable, we are offline
// for any other error, rethrow it
if (err.code === "unavailable")
return false;
throw err;
}
);
}
/**
* A function that attaches a listener to when a connection to Firestore has
* been established or when is disconnected.
*
* This function listens to the non-existant `/.info/connected` document and
* uses it's `fromCache` metadata to **estimate** whether a connection to
* Firestore is currently available.
* **Note:** This callback will only be invoked after the first successful
* connection to Firestore
*
* #param {((error: unknown | null, isOnline: boolean) => unknown)} callback the
* callback to invoke when the isOnline state changes
* #return {(() => void)} a function that unsubscribes this listener when
* invoked
*/
function onOnline(callback) {
let hasConnected = false;
// unlike RTDB, this data doesn't exist and has no function
// must be made readable in security rules
return firebase.firestore()
.doc(".info/connected")
.onSnapshot(
{ includeMetadataChanges: "server" },
{
next(snapshot) {
const { fromCache } = snapshot.metadata;
if (!hasConnected) {
if (fromCache) return; // ignore this event
hasConnected = true;
}
callback(null, !fromCache);
},
error(err) {
callback(err);
}
}
);
}

Realm Object Server: Access Denied Error after successful login using Custom Authentication

I am trying to setup a Realm Object Server for my company's mobile application. I have to use a custom authentication to allow users to access the database.
import { BasicServer } from 'realm-object-server'
import * as path from 'path'
import { AuthProvider } from './lib/auth'
const server = new BasicServer()
server.start({
dataPath: path.join(__dirname, '../data'),
address: '192.168.0.24',
authProviders: [new AuthProvider()]
})
.then(() => {
console.log(`Realm Object Server was started on ${server.address}`)
})
.catch(err => {
console.error(`Error starting Realm Object Server: ${err.message}`)
})
Here is the custom auth that I have to apply. The authentication will be done by another backend server.
import { post } from 'superagent'
import { auth, User, errors } from 'realm-object-server'
import { pick } from 'lodash';
export class AuthProvider extends auth.AuthProvider {
name = 'authprovider'
authenticateOrCreateUser(body: any): Promise<User> {
return post('https://XYZ/signin')
.send({
'email': body.user_info.email,
'password': body.user_info.password
})
.then((successResponseJSON: any) => {
return this.service.createOrUpdateUser(
successResponseJSON.body.id,
this.name, // this is the name of the provider,
false, // this is if the user should or should not be an admin
pick(successResponseJSON.body, ['id', 'email'])
)
})
.catch(err => {
throw new errors.realm.InvalidCredentials({ detail: err })
})
}
}
I have added code for custom authentication to the example for provided by realm to add data to the realm server. Here I am asking that the user be authenticated using 'authprovider'
var URL = "192.168.0.24:9080"
Realm.Sync.User.registerWithProvider(`http://${URL}`, {
provider: 'authprovider',
providerToken: null,
userInfo: {
email: username,
password: password
}
}).then(user => {
console.log('user', user, user.identity)
Realm.open({
sync: {
url: `realm://${URL}/abc`,
user: user
},
schema: [TickerSchema],
})
Even though the user is successfully authenticated, I am getting access denied error. I am not able to understand why.
user User {} 9ae6033cd9b55e3aca62a291af8726ea
Unhandled session token refresh error { Error: The path is invalid or current user has no access.
at new AuthError (/home/sukumar/code_snippets/realm-test/node_modules/realm/lib/errors.js:22:25)
at performFetch.then.then (/home/sukumar/code_snippets/realm-test/node_modules/realm/lib/user-methods.js:105:29)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
name: 'AuthError',
message: 'The path is invalid or current user has no access.',
stack: 'Error: The path is invalid or current user has no access.\n at new AuthError (/home/sukumar/code_snippets/realm-test/node_modules/realm/lib/errors.js:22:25)\n at performFetch.then.then (/home/sukumar/code_snippets/realm-test/node_modules/realm/lib/user-methods.js:105:29)\n at <anonymous>\n at process._tickCallback (internal/process/next_tick.js:188:7)',
type: 'https://realm.io/docs/object-server/problems/access-denied',
title: 'The path is invalid or current user has no access.',
status: 403,
code: 614 }
The realm url was incorrect: it should have been realm://${URL}/~/abc instead of realm://${URL}/abc

Resources