-
Notifications
You must be signed in to change notification settings - Fork 4.4k
🐛 Bug Report: users cannot update documents where they have update permissions when there is a relationship #5852
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@t0mm4rx, thanks for raising this issue! 🙏🏼 Unfortunately, I was unable to reproduce your issue. I have a document with document-level permissions enabled: {
"total": 1,
"documents": [
{
"name": "asdf",
"$id": "level1",
"$createdAt": "2023-06-01T18:49:33.582+00:00",
"$updatedAt": "2023-07-20T03:12:56.879+00:00",
"$permissions": [
"read(\"user:joe\")",
"update(\"user:joe\")",
"delete(\"user:joe\")"
],
"level2": [
{
"$id": "level2",
"$createdAt": "2023-06-01T18:49:33.583+00:00",
"$updatedAt": "2023-07-20T03:12:56.871+00:00",
"$permissions": [
"read(\"user:joe\")",
"update(\"user:joe\")",
"delete(\"user:joe\")"
],
"level3": [
{
"$id": "level3",
"$createdAt": "2023-06-01T18:49:33.586+00:00",
"$updatedAt": "2023-07-20T03:12:56.861+00:00",
"$permissions": [
"read(\"user:joe\")",
"update(\"user:joe\")",
"delete(\"user:joe\")"
],
"$databaseId": "one-to-many",
"$collectionId": "level3"
}
],
"$databaseId": "one-to-many",
"$collectionId": "level2"
}
],
"$databaseId": "one-to-many",
"$collectionId": "level1"
}
]
} I created an update request and it was successful: Are you able to reproduce the errors when following your reproduction steps from a fresh project? |
Have you disabled all permissions on the collection rights? I have also forgotten to mention that this is a two-way relationship. This bug (and all the other relationship bugs I created yesterday) start happening more and more as the database gets heavier (> 50k documents, > 10 relationships for each doc). Maybe you could populate a database with a random dataset to perform these tests. |
I just reproduced a similar bug from a fresh install. The bug appears with an admin API key, so it seems unrelated to document security. Here is a backup of my instance: https://drive.google.com/file/d/1QI3YN3Nze_rCXuzl8rKmMgUbcz42YJEv/view?usp=sharing Here is the code I run that triggers the 500 error: const a = await db.createDocument("test", "connections", "unique()", {
name: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
description: "lorem"
})
console.log(a)
await db.createDocument("test", "profiles", "unique()", {
name: "ab",
description: "lorem",
connections: [a],
connections2: [a],
}) Here is the
|
All of these 500 errors seem to appear after a certain set of operations (delete, update) on relationships. They might be related to the same underlying issue. |
I can confirm this issue also. The issue seems specific to the use of the API key because I can modify all collections fine when using a logged in user from my Flutter application. |
Hello, I found a fix to this error, and it's quite strange. First, I need to mention that updating a document with a lot of relationships inside could be very long. It takes almost 30 seconds to update a string attribute with 2000 relationships. When send the whole array of relationships as IDs when updating a doc, both issues disapear. For example: /**
* Either takes a very long time, or yields a 401.
*/
database.updateDocument('my-db', 'collection-a', 'document-a', {
randomAttribute: 'xyz'
})
/**
* No 401, and 100x faster
*/
database.updateDocument('my-db', 'collection-a', 'document-a', {
randomAttribute: 'xyz',
relations: ['doc-1', 'doc-2', ...]
}) |
Hey @t0mm4rx, there were changes to the permissions logic relating to your original issue in 1.4.x, are you still able to reproduce the root issue in the latest version? |
Closing as fixed in 1.4.2 |
I can confirm this issue is still present and can be replicated. While my initial function was more complex, to replicate the issue I have a barebones version of the function code below. import 'dart:convert';
import 'dart:io';
import 'package:dart_appwrite/dart_appwrite.dart';
bool checkEnvVariables() {
if (Platform.environment['APPWRITE_FUNCTION_ENDPOINT'] == null ||
Platform.environment['APPWRITE_FUNCTION_PROJECT_ID'] == null ||
Platform.environment['APPWRITE_FUNCTION_API_KEY'] == null ||
Platform.environment['DATABASEID'] == null ||
Platform.environment['VULNERABILITIESCOLLECTIONID'] == null ||
Platform.environment['APPLICATIONSCOLLECTIONID'] == null ||
Platform.environment['SERVERSCOLLECTIONID'] == null ||
Platform.environment['PORTSCOLLECTIONID'] == null ||
Platform.environment['CVECOLLECTIONID'] == null ||
Platform.environment['TIERCOLLECTIONID'] == null ||
Platform.environment['TERRITORYCOLLECTIONID'] == null) {
return false;
}
return true;
}
bool checkPayload(Map<String, dynamic> payload) {
if (payload['\$id'] == null || payload['name'] == null || payload['bucketId'] == null) {
return false;
}
return true;
}
bool hasPayload(String payload) {
if (payload == "") {
return false;
}
return true;
}
Future<dynamic> main(final context) async {
if (!checkEnvVariables()) {
return Communication.returnFailure(context, "Some Environment variables are not set");
}
final client = Client();
client
.setEndpoint(Platform.environment['APPWRITE_FUNCTION_ENDPOINT']!)
.setProject(Platform.environment['APPWRITE_FUNCTION_PROJECT_ID']!)
.setKey(Platform.environment['APPWRITE_FUNCTION_API_KEY']!)
.setSelfSigned(status: true);
final database = Databases(client);
context.log(jsonEncode(context.req.headers));
if (!hasPayload(context.req.body)) {
return Communication.returnFailure(context, "No payload data");
}
final payload = jsonDecode(context.req.body);
if (!checkPayload(payload)) {
return Communication.returnFailure(context, "Payload has incorrect data");
}
context.log(payload);
final String fileId = payload['\$id'];
final String fileName = payload['name'];
final String bucketId = payload['bucketId'];
final String applicationName = fileName.split('_')[4];
try {
await database.createDocument(
databaseId: Platform.environment['DATABASEID']!,
collectionId: Platform.environment['APPLICATIONSCOLLECTIONID']!,
documentId: "6499af4d385699723b3b",
data: {"appName": "CRM"},
);
} on AppwriteException catch (e, s) {
return Communication.returnFailure(context, 'Error Creating New Application', e: e.toString(), s: s.toString());
} catch (e, s) {
return Communication.returnFailure(context, 'Unknown Error Creating New Application', e: e.toString(), s: s.toString());
}
try {
await database.createDocument(
databaseId: Platform.environment['DATABASEID']!,
collectionId: Platform.environment['TERRITORYCOLLECTIONID']!,
documentId: "649326a4684872634a46",
data: {"name": "US"},
);
} on AppwriteException catch (e, s) {
return Communication.returnFailure(context, 'Error Creating New Territory', e: e.toString(), s: s.toString());
} catch (e, s) {
return Communication.returnFailure(context, 'Unknown Error Creating New Territory', e: e.toString(), s: s.toString());
}
try {
await database.createDocument(
databaseId: Platform.environment['DATABASEID']!,
collectionId: Platform.environment['SERVERSCOLLECTIONID']!,
documentId: "64a6d0fba36f48ebe963",
data: {
"ip": "192.168.0.1",
"hostType": "Linux",
"territories": {"\$id": "649326a4684872634a46", "name": "US"},
"applications": {"\$id": "6499af4d385699723b3b", "appName": "CRM"},
"name": "us-crm-dbs"
},
);
} on AppwriteException catch (e, s) {
return Communication.returnFailure(context, 'Error Creating New Server', e: e.toString(), s: s.toString());
} catch (e, s) {
return Communication.returnFailure(context, 'Unknown Error Creating New Server', e: e.toString(), s: s.toString());
}
try {
await database.createDocument(
databaseId: Platform.environment['DATABASEID']!,
collectionId: Platform.environment['PORTSCOLLECTIONID']!,
documentId: "64d3c52984c0f768ac83",
data: {"portNo": 3389, "connectionType": "tcp"},
);
} on AppwriteException catch (e, s) {
return Communication.returnFailure(context, 'Error Creating New Port', e: e.toString(), s: s.toString());
} catch (e, s) {
return Communication.returnFailure(context, 'Unknown Error Creating New Port', e: e.toString(), s: s.toString());
}
try {
await database.createDocument(
databaseId: Platform.environment['DATABASEID']!,
collectionId: Platform.environment['VULNERABILITIESCOLLECTIONID']!,
documentId: ID.unique(),
data: {
"servers": {
"\$id": "64a6d0fba36f48ebe963",
"ip": "192.168.0.1",
"hostType": "Linux",
"territories": {"\$id": "649326a4684872634a46", "name": "T"},
"applications": {"\$id": "6499af4d385699723b3b", "appName": "CRM"},
"name": "tt-crm-dbs"
},
"ports": [
{"\$id": "64d3c52984c0f768ac83", "portNo": 3389, "connectionType": "tcp"}
],
"classType": null,
"applications": {"\$id": "6499af4d385699723b3b", "appName": "CRM"},
"severity": "Low",
"cve": [],
"detail": "SSL certificate is self signed"
},
);
} on AppwriteException catch (e, s) {
return Communication.returnFailure(context, 'Error Creating New Vulnerability', e: e.toString(), s: s.toString());
} catch (e, s) {
return Communication.returnFailure(context, 'Unknown Error Creating New Vulnerability', e: e.toString(), s: s.toString());
}
return Communication.returnSuccess(context, "Success");
}
class Communication {
static void returnSuccess(final context, final message) {
context.log(message);
context.res.json({
'success': true,
'message': message,
});
}
static dynamic returnFailure(final context, final String message, {String e = '', String s = ''}) {
context.log(message);
if (e.isNotEmpty) {
context.error(e);
}
if (s.isNotEmpty) {
context.error(s);
}
return context.res.json({
'success': false,
'message': message,
});
}
} appwrite.json.txt |
Adding same permissions on the relationship(related docs) solved it for me |
👟 Reproduction steps
Hello,
I have collections A and B. Both have document security enabled.
A has a one-to-many relationship attribute with B.
X is a document in A, the user has update rights.
Z is a document in B, the user has update rights.
Z is inside of X.
When updating a field of X, the user gets a
401
. Here are the logs of theappwrite
container:The error is thrown in this block code:
appwrite/app/controllers/api/databases.php
Line 3295 in 9fafd39
This block is check for
!$documentSecurity
, and both collection hasdocumentSecurity
enabled, so it might be an error done while computing this variable.Here is a Discord post discussing the issue: https://ptb.discord.com/channels/564160730845151244/1125081645322604554
👍 Expected behavior
The user should be able to update its document.
👎 Actual Behavior
The user cannot update the document where he has the rights to.
🎲 Appwrite version
Version 1.3.x
💻 Operating system
Linux
🧱 Your Environment
Self-deployed 1.3.7.
👀 Have you spent some time to check if this issue has been raised before?
🏢 Have you read the Code of Conduct?
The text was updated successfully, but these errors were encountered: