mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
64
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e6165fcbe | ||
|
|
8a52975048 | ||
|
|
45e3267930 | ||
|
|
2b96d60c1e | ||
|
|
417bb22790 | ||
|
|
1b70bc812b | ||
|
|
e7e429142f | ||
|
|
774e3af61c | ||
|
|
a0514d2aac | ||
|
|
ac137cee3d | ||
|
|
58e091099f | ||
|
|
6410a245eb | ||
|
|
670edd845e | ||
|
|
834c18f9fa | ||
|
|
77930a0cec | ||
|
|
5d9201466b | ||
|
|
d583b5e228 | ||
|
|
c463a9a662 | ||
|
|
bd9f02b689 | ||
|
|
472e2c282d | ||
|
|
7a89779827 | ||
|
|
126de78ce2 | ||
|
|
e919896eef | ||
|
|
fd3475f945 | ||
|
|
9c8f565211 | ||
|
|
08f30224b6 | ||
|
|
6d02554f2a | ||
|
|
61c619f373 | ||
|
|
b32dd316e1 | ||
|
|
22042b4749 | ||
|
|
aa17eeb6e3 | ||
|
|
1529357821 | ||
|
|
3a98361736 | ||
|
|
0c425dbac3 | ||
|
|
69b861cd87 | ||
|
|
0599d23cc5 | ||
|
|
a37b4a40d9 | ||
|
|
7e37046959 | ||
|
|
f9efdfd98e | ||
|
|
d53090647b | ||
|
|
e8b8a8fe52 | ||
|
|
73d3d15ed8 | ||
|
|
b78be65376 | ||
|
|
c3bc3dcb3b | ||
|
|
0e75793bef | ||
|
|
2f4a362e1b | ||
|
|
cda843d8f6 | ||
|
|
d6a40a35ee | ||
|
|
e111b4cc18 | ||
|
|
58751bbdf1 | ||
|
|
21334ecdff | ||
|
|
47ea2893c3 | ||
|
|
cf90653deb | ||
|
|
16fb25ce5a | ||
|
|
e78887001a | ||
|
|
aa4ecdf138 | ||
|
|
3783378288 | ||
|
|
5aff78a619 | ||
|
|
62b391ef68 | ||
|
|
6f1d2d094a | ||
|
|
88bd35ce98 | ||
|
|
db0dbeb27b | ||
|
|
0e27088e2a | ||
|
|
70a7deaa38 |
@@ -101,6 +101,7 @@ _APP_USAGE_AGGREGATION_INTERVAL=30
|
||||
_APP_STATS_RESOURCES_INTERVAL=30
|
||||
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
|
||||
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
|
||||
_APP_INTERVAL_DOMAIN_VERIFICATION=60
|
||||
_APP_USAGE_STATS=enabled
|
||||
_APP_LOGGING_CONFIG=
|
||||
_APP_LOGGING_CONFIG_REALTIME=
|
||||
|
||||
@@ -57,6 +57,7 @@ RUN mkdir -p /storage/uploads && \
|
||||
# Executables
|
||||
RUN chmod +x /usr/local/bin/doctor && \
|
||||
chmod +x /usr/local/bin/install && \
|
||||
chmod +x /usr/local/bin/interval && \
|
||||
chmod +x /usr/local/bin/maintenance && \
|
||||
chmod +x /usr/local/bin/migrate && \
|
||||
chmod +x /usr/local/bin/realtime && \
|
||||
|
||||
+3
-1
@@ -116,6 +116,7 @@ return [
|
||||
[
|
||||
'key' => 'android',
|
||||
'name' => 'Android',
|
||||
'namespace' => 'io.appwrite',
|
||||
'version' => '11.4.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-android',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
|
||||
@@ -226,7 +227,7 @@ return [
|
||||
[
|
||||
'key' => 'cli',
|
||||
'name' => 'Command Line',
|
||||
'version' => '12.0.1',
|
||||
'version' => '13.0.0-rc.2',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-cli',
|
||||
'package' => 'https://www.npmjs.com/package/appwrite-cli',
|
||||
'enabled' => true,
|
||||
@@ -395,6 +396,7 @@ return [
|
||||
[
|
||||
'key' => 'kotlin',
|
||||
'name' => 'Kotlin',
|
||||
'namespace' => 'io.appwrite',
|
||||
'version' => '13.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
|
||||
|
||||
@@ -407,8 +407,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -429,7 +429,23 @@
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
]
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"duration": {
|
||||
"type": "integer",
|
||||
"description": "Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.",
|
||||
"x-example": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"\/account\/logs": {
|
||||
@@ -535,7 +551,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMFA",
|
||||
"group": "mfa",
|
||||
"weight": 306,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa.md",
|
||||
@@ -607,7 +623,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 308,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-authenticator.md",
|
||||
@@ -731,7 +747,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 309,
|
||||
"weight": 310,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-authenticator.md",
|
||||
@@ -871,7 +887,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 310,
|
||||
"weight": 311,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/delete-mfa-authenticator.md",
|
||||
@@ -995,7 +1011,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 314,
|
||||
"weight": 315,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-challenge.md",
|
||||
@@ -1129,7 +1145,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 315,
|
||||
"weight": 316,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-challenge.md",
|
||||
@@ -1267,7 +1283,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listMfaFactors",
|
||||
"group": "mfa",
|
||||
"weight": 307,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/list-mfa-factors.md",
|
||||
@@ -1368,7 +1384,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 313,
|
||||
"weight": 314,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/get-mfa-recovery-codes.md",
|
||||
@@ -1467,7 +1483,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 311,
|
||||
"weight": 312,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-recovery-codes.md",
|
||||
@@ -1566,7 +1582,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 312,
|
||||
"weight": 313,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-recovery-codes.md",
|
||||
@@ -2558,7 +2574,8 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock"
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": []
|
||||
@@ -3488,7 +3505,8 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock"
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": []
|
||||
@@ -5825,7 +5843,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": null,
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-keys": [],
|
||||
"default": ""
|
||||
},
|
||||
@@ -5858,7 +5876,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 380,
|
||||
"weight": 381,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-transactions.md",
|
||||
@@ -5925,7 +5943,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 376,
|
||||
"weight": 377,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-transaction.md",
|
||||
@@ -5995,7 +6013,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 377,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-transaction.md",
|
||||
@@ -6059,7 +6077,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 378,
|
||||
"weight": 379,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-transaction.md",
|
||||
@@ -6137,7 +6155,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 379,
|
||||
"weight": 380,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-transaction.md",
|
||||
@@ -6203,7 +6221,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 381,
|
||||
"weight": 382,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-operations.md",
|
||||
@@ -6288,7 +6306,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listDocuments",
|
||||
"group": "documents",
|
||||
"weight": 339,
|
||||
"weight": 340,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-documents.md",
|
||||
@@ -6400,7 +6418,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createDocument",
|
||||
"group": "documents",
|
||||
"weight": 331,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-document.md",
|
||||
@@ -6561,7 +6579,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getDocument",
|
||||
"group": "documents",
|
||||
"weight": 332,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-document.md",
|
||||
@@ -6672,7 +6690,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertDocument",
|
||||
"group": "documents",
|
||||
"weight": 335,
|
||||
"weight": 336,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/upsert-document.md",
|
||||
@@ -6827,7 +6845,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateDocument",
|
||||
"group": "documents",
|
||||
"weight": 333,
|
||||
"weight": 334,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-document.md",
|
||||
@@ -6939,7 +6957,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"group": "documents",
|
||||
"weight": 337,
|
||||
"weight": 338,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-document.md",
|
||||
@@ -7046,7 +7064,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 342,
|
||||
"weight": 343,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/decrement-document-attribute.md",
|
||||
@@ -7173,7 +7191,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 341,
|
||||
"weight": 342,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/increment-document-attribute.md",
|
||||
@@ -7300,7 +7318,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 472,
|
||||
"weight": 473,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -7387,7 +7405,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 470,
|
||||
"weight": 471,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -7505,7 +7523,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 471,
|
||||
"weight": 472,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7580,7 +7598,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"group": "graphql",
|
||||
"weight": 241,
|
||||
"weight": 242,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/query.md",
|
||||
@@ -7634,7 +7652,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"group": "graphql",
|
||||
"weight": 240,
|
||||
"weight": 241,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/mutation.md",
|
||||
@@ -8120,7 +8138,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 290,
|
||||
"weight": 291,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/create-subscriber.md",
|
||||
@@ -8204,7 +8222,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 294,
|
||||
"weight": 295,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/delete-subscriber.md",
|
||||
@@ -9113,7 +9131,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 445,
|
||||
"weight": 446,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-transactions.md",
|
||||
@@ -9183,7 +9201,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 441,
|
||||
"weight": 442,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-transaction.md",
|
||||
@@ -9256,7 +9274,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 442,
|
||||
"weight": 443,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-transaction.md",
|
||||
@@ -9323,7 +9341,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 443,
|
||||
"weight": 444,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-transaction.md",
|
||||
@@ -9404,7 +9422,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 444,
|
||||
"weight": 445,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-transaction.md",
|
||||
@@ -9473,7 +9491,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 446,
|
||||
"weight": 447,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-operations.md",
|
||||
@@ -9561,7 +9579,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 437,
|
||||
"weight": 438,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -9672,7 +9690,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 429,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -9828,7 +9846,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 430,
|
||||
"weight": 431,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -9938,7 +9956,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 433,
|
||||
"weight": 434,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -10088,7 +10106,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 431,
|
||||
"weight": 432,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -10199,7 +10217,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 435,
|
||||
"weight": 436,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -10305,7 +10323,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 440,
|
||||
"weight": 441,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -10431,7 +10449,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 439,
|
||||
"weight": 440,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -407,8 +407,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -5843,7 +5843,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": null,
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-keys": [],
|
||||
"default": ""
|
||||
},
|
||||
|
||||
@@ -442,8 +442,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -5836,7 +5836,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": null,
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-keys": [],
|
||||
"default": ""
|
||||
},
|
||||
|
||||
@@ -412,8 +412,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -5567,7 +5567,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": null,
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-keys": [],
|
||||
"default": ""
|
||||
},
|
||||
|
||||
@@ -464,8 +464,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -486,6 +486,23 @@
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"duration": {
|
||||
"type": "integer",
|
||||
"description": "Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.",
|
||||
"default": 900,
|
||||
"x-example": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -591,7 +608,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMFA",
|
||||
"group": "mfa",
|
||||
"weight": 306,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa.md",
|
||||
@@ -666,7 +683,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 308,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-authenticator.md",
|
||||
@@ -790,7 +807,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 309,
|
||||
"weight": 310,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-authenticator.md",
|
||||
@@ -931,7 +948,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 310,
|
||||
"weight": 311,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/delete-mfa-authenticator.md",
|
||||
@@ -1055,7 +1072,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 314,
|
||||
"weight": 315,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-challenge.md",
|
||||
@@ -1192,7 +1209,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 315,
|
||||
"weight": 316,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-challenge.md",
|
||||
@@ -1332,7 +1349,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listMfaFactors",
|
||||
"group": "mfa",
|
||||
"weight": 307,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/list-mfa-factors.md",
|
||||
@@ -1433,7 +1450,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 313,
|
||||
"weight": 314,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/get-mfa-recovery-codes.md",
|
||||
@@ -1534,7 +1551,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 311,
|
||||
"weight": 312,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-recovery-codes.md",
|
||||
@@ -1635,7 +1652,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 312,
|
||||
"weight": 313,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-recovery-codes.md",
|
||||
@@ -2667,7 +2684,8 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock"
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": [],
|
||||
@@ -3621,7 +3639,8 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock"
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": [],
|
||||
@@ -5931,7 +5950,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": null,
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-keys": [],
|
||||
"default": "",
|
||||
"in": "query"
|
||||
@@ -5963,7 +5982,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 380,
|
||||
"weight": 381,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-transactions.md",
|
||||
@@ -6030,7 +6049,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 376,
|
||||
"weight": 377,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-transaction.md",
|
||||
@@ -6100,7 +6119,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 377,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-transaction.md",
|
||||
@@ -6163,7 +6182,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 378,
|
||||
"weight": 379,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-transaction.md",
|
||||
@@ -6242,7 +6261,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 379,
|
||||
"weight": 380,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-transaction.md",
|
||||
@@ -6307,7 +6326,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 381,
|
||||
"weight": 382,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-operations.md",
|
||||
@@ -6388,7 +6407,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listDocuments",
|
||||
"group": "documents",
|
||||
"weight": 339,
|
||||
"weight": 340,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-documents.md",
|
||||
@@ -6492,7 +6511,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createDocument",
|
||||
"group": "documents",
|
||||
"weight": 331,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-document.md",
|
||||
@@ -6651,7 +6670,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getDocument",
|
||||
"group": "documents",
|
||||
"weight": 332,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-document.md",
|
||||
@@ -6754,7 +6773,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertDocument",
|
||||
"group": "documents",
|
||||
"weight": 335,
|
||||
"weight": 336,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/upsert-document.md",
|
||||
@@ -6905,7 +6924,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateDocument",
|
||||
"group": "documents",
|
||||
"weight": 333,
|
||||
"weight": 334,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-document.md",
|
||||
@@ -7015,7 +7034,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"group": "documents",
|
||||
"weight": 337,
|
||||
"weight": 338,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-document.md",
|
||||
@@ -7116,7 +7135,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 342,
|
||||
"weight": 343,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/decrement-document-attribute.md",
|
||||
@@ -7237,7 +7256,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 341,
|
||||
"weight": 342,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/increment-document-attribute.md",
|
||||
@@ -7356,7 +7375,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 472,
|
||||
"weight": 473,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -7439,7 +7458,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 470,
|
||||
"weight": 471,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -7558,7 +7577,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 471,
|
||||
"weight": 472,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7630,7 +7649,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"group": "graphql",
|
||||
"weight": 241,
|
||||
"weight": 242,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/query.md",
|
||||
@@ -7705,7 +7724,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"group": "graphql",
|
||||
"weight": 240,
|
||||
"weight": 241,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/mutation.md",
|
||||
@@ -8204,7 +8223,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 290,
|
||||
"weight": 291,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/create-subscriber.md",
|
||||
@@ -8289,7 +8308,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 294,
|
||||
"weight": 295,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/delete-subscriber.md",
|
||||
@@ -9146,7 +9165,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 445,
|
||||
"weight": 446,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-transactions.md",
|
||||
@@ -9216,7 +9235,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 441,
|
||||
"weight": 442,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-transaction.md",
|
||||
@@ -9289,7 +9308,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 442,
|
||||
"weight": 443,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-transaction.md",
|
||||
@@ -9355,7 +9374,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 443,
|
||||
"weight": 444,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-transaction.md",
|
||||
@@ -9437,7 +9456,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 444,
|
||||
"weight": 445,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-transaction.md",
|
||||
@@ -9505,7 +9524,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 446,
|
||||
"weight": 447,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-operations.md",
|
||||
@@ -9589,7 +9608,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 437,
|
||||
"weight": 438,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -9692,7 +9711,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 429,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -9846,7 +9865,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 430,
|
||||
"weight": 431,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -9948,7 +9967,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 433,
|
||||
"weight": 434,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -10094,7 +10113,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 431,
|
||||
"weight": 432,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -10203,7 +10222,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 435,
|
||||
"weight": 436,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -10303,7 +10322,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 440,
|
||||
"weight": 441,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -10423,7 +10442,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 439,
|
||||
"weight": 440,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -464,8 +464,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -5950,7 +5950,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": null,
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-keys": [],
|
||||
"default": "",
|
||||
"in": "query"
|
||||
|
||||
@@ -509,8 +509,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -5953,7 +5953,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": null,
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-keys": [],
|
||||
"default": "",
|
||||
"in": "query"
|
||||
|
||||
@@ -478,8 +478,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -5680,7 +5680,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": null,
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-keys": [],
|
||||
"default": "",
|
||||
"in": "query"
|
||||
|
||||
@@ -2955,7 +2955,8 @@ App::post('/v1/account/jwts')
|
||||
contentType: ContentType::JSON,
|
||||
))
|
||||
->param('duration', 900, new Range(0, 3600), 'Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.', true)
|
||||
->label('abuse-limit', 100)
|
||||
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT * 2)
|
||||
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
|
||||
->label('abuse-key', 'url:{url},userId:{userId}')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
|
||||
@@ -461,7 +461,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
// Add permissions for current the user if none were provided.
|
||||
if (\is_null($permissions)) {
|
||||
$permissions = [];
|
||||
if (!empty($user->getId())) {
|
||||
if (!empty($user->getId()) && !$isPrivilegedUser) {
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$permissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
}
|
||||
@@ -470,7 +470,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = Authorization::getRoles();
|
||||
if (!User::isApp($roles) && !User::isPrivileged($roles)) {
|
||||
if (!$isAPIKey && !$isPrivilegedUser) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
|
||||
@@ -1048,18 +1048,15 @@ App::init()
|
||||
if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) {
|
||||
$cache[$domain->get()] = false;
|
||||
Config::setParam('hostnames', $cache);
|
||||
Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
|
||||
Console::warning('Skipping SSL certificates generation on ACME challenge.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Check if domain is a main domain
|
||||
if (!in_array($domain->get(), $platformHostnames)) {
|
||||
Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
php /usr/src/code/app/cli.php interval $@
|
||||
Generated
+48
-48
@@ -3654,16 +3654,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
"version": "0.13.1",
|
||||
"version": "0.13.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/cache.git",
|
||||
"reference": "97220cb3b3822b166ee016d1646e2ae2815dc540"
|
||||
"reference": "5768498c9f451482f0bf3eede4d6452ddcd4a0f6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/cache/zipball/97220cb3b3822b166ee016d1646e2ae2815dc540",
|
||||
"reference": "97220cb3b3822b166ee016d1646e2ae2815dc540",
|
||||
"url": "https://api.github.com/repos/utopia-php/cache/zipball/5768498c9f451482f0bf3eede4d6452ddcd4a0f6",
|
||||
"reference": "5768498c9f451482f0bf3eede4d6452ddcd4a0f6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3672,7 +3672,7 @@
|
||||
"ext-redis": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
"utopia-php/telemetry": "0.1.*"
|
||||
"utopia-php/telemetry": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
@@ -3700,9 +3700,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/cache/issues",
|
||||
"source": "https://github.com/utopia-php/cache/tree/0.13.1"
|
||||
"source": "https://github.com/utopia-php/cache/tree/0.13.2"
|
||||
},
|
||||
"time": "2025-05-09T14:43:52+00:00"
|
||||
"time": "2025-12-17T08:55:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cli",
|
||||
@@ -3896,16 +3896,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "3.6.0",
|
||||
"version": "3.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "af15066255a5fd7bd2926de37bcbf3d8500fc155"
|
||||
"reference": "c8c1b2f5770245dd4006e2680681e3efbe8b1fa7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/af15066255a5fd7bd2926de37bcbf3d8500fc155",
|
||||
"reference": "af15066255a5fd7bd2926de37bcbf3d8500fc155",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/c8c1b2f5770245dd4006e2680681e3efbe8b1fa7",
|
||||
"reference": "c8c1b2f5770245dd4006e2680681e3efbe8b1fa7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3948,9 +3948,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/3.6.0"
|
||||
"source": "https://github.com/utopia-php/database/tree/3.6.1"
|
||||
},
|
||||
"time": "2025-12-08T05:23:04+00:00"
|
||||
"time": "2025-12-16T09:55:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -3999,23 +3999,23 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/dns",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/dns.git",
|
||||
"reference": "dce3453364a4524b7250db8d8eb74820b814409e"
|
||||
"reference": "5daf8b683dad877491c4df84c6be24850b2f363b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/dns/zipball/dce3453364a4524b7250db8d8eb74820b814409e",
|
||||
"reference": "dce3453364a4524b7250db8d8eb74820b814409e",
|
||||
"url": "https://api.github.com/repos/utopia-php/dns/zipball/5daf8b683dad877491c4df84c6be24850b2f363b",
|
||||
"reference": "5daf8b683dad877491c4df84c6be24850b2f363b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
"utopia-php/console": "0.0.*",
|
||||
"utopia-php/domains": "0.9.*",
|
||||
"utopia-php/telemetry": "0.1.*",
|
||||
"utopia-php/telemetry": "*",
|
||||
"utopia-php/validators": "0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -4050,9 +4050,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/dns/issues",
|
||||
"source": "https://github.com/utopia-php/dns/tree/1.4.0"
|
||||
"source": "https://github.com/utopia-php/dns/tree/1.4.1"
|
||||
},
|
||||
"time": "2025-12-05T10:09:00+00:00"
|
||||
"time": "2025-12-17T09:09:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
@@ -4730,21 +4730,21 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/pools",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/pools.git",
|
||||
"reference": "05c67aba42eb68ac65489cc1e7fc5db83db2dd4d"
|
||||
"reference": "ad7d6ba946376e81c603204285ce9a674b6502b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/pools/zipball/05c67aba42eb68ac65489cc1e7fc5db83db2dd4d",
|
||||
"reference": "05c67aba42eb68ac65489cc1e7fc5db83db2dd4d",
|
||||
"url": "https://api.github.com/repos/utopia-php/pools/zipball/ad7d6ba946376e81c603204285ce9a674b6502b8",
|
||||
"reference": "ad7d6ba946376e81c603204285ce9a674b6502b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
"utopia-php/telemetry": "0.1.*"
|
||||
"php": ">=8.4",
|
||||
"utopia-php/telemetry": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
@@ -4776,9 +4776,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/pools/issues",
|
||||
"source": "https://github.com/utopia-php/pools/tree/0.8.2"
|
||||
"source": "https://github.com/utopia-php/pools/tree/0.8.3"
|
||||
},
|
||||
"time": "2025-04-17T02:04:54+00:00"
|
||||
"time": "2025-12-17T09:35:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/preloader",
|
||||
@@ -4835,16 +4835,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/queue",
|
||||
"version": "0.11.1",
|
||||
"version": "0.11.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/queue.git",
|
||||
"reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6"
|
||||
"reference": "a854f7c4abc18e0eca55fc5608cd7088d71eb19f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/queue/zipball/498bbbef418b1db71b51e1bb62f5d1d752ddd8d6",
|
||||
"reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6",
|
||||
"url": "https://api.github.com/repos/utopia-php/queue/zipball/a854f7c4abc18e0eca55fc5608cd7088d71eb19f",
|
||||
"reference": "a854f7c4abc18e0eca55fc5608cd7088d71eb19f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4854,7 +4854,7 @@
|
||||
"utopia-php/fetch": "0.4.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
"utopia-php/telemetry": "0.1.*"
|
||||
"utopia-php/telemetry": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-redis": "*",
|
||||
@@ -4895,9 +4895,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/queue/issues",
|
||||
"source": "https://github.com/utopia-php/queue/tree/0.11.1"
|
||||
"source": "https://github.com/utopia-php/queue/tree/0.11.2"
|
||||
},
|
||||
"time": "2025-05-30T11:50:34+00:00"
|
||||
"time": "2025-12-17T09:32:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/registry",
|
||||
@@ -4953,16 +4953,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/storage",
|
||||
"version": "0.18.16",
|
||||
"version": "0.18.18",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/storage.git",
|
||||
"reference": "0c7b8ad68de8e1eb23ccc8af9f27a30eb832930f"
|
||||
"reference": "acaea524f315f87b8811a2c34450fe2b502f49d8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/storage/zipball/0c7b8ad68de8e1eb23ccc8af9f27a30eb832930f",
|
||||
"reference": "0c7b8ad68de8e1eb23ccc8af9f27a30eb832930f",
|
||||
"url": "https://api.github.com/repos/utopia-php/storage/zipball/acaea524f315f87b8811a2c34450fe2b502f49d8",
|
||||
"reference": "acaea524f315f87b8811a2c34450fe2b502f49d8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5005,9 +5005,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/storage/issues",
|
||||
"source": "https://github.com/utopia-php/storage/tree/0.18.16"
|
||||
"source": "https://github.com/utopia-php/storage/tree/0.18.18"
|
||||
},
|
||||
"time": "2025-12-03T02:15:45+00:00"
|
||||
"time": "2025-12-17T07:33:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/swoole",
|
||||
@@ -5436,16 +5436,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.5.9",
|
||||
"version": "1.7.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "ee434aa00a9185380b9a39bb46bf86d7104d3a93"
|
||||
"reference": "3876d486e2c00b788fbda677ef9fcc77391b8898"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/ee434aa00a9185380b9a39bb46bf86d7104d3a93",
|
||||
"reference": "ee434aa00a9185380b9a39bb46bf86d7104d3a93",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/3876d486e2c00b788fbda677ef9fcc77391b8898",
|
||||
"reference": "3876d486e2c00b788fbda677ef9fcc77391b8898",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5481,9 +5481,9 @@
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.5.9"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.7.2"
|
||||
},
|
||||
"time": "2025-11-25T05:22:25+00:00"
|
||||
"time": "2025-12-24T07:49:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@@ -8943,7 +8943,7 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
||||
@@ -555,6 +555,7 @@ services:
|
||||
- _APP_DOMAIN_TARGET_CAA
|
||||
- _APP_DNS
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_EMAIL_CERTIFICATES
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
@@ -753,6 +754,7 @@ services:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -785,6 +787,43 @@ services:
|
||||
- _APP_MAINTENANCE_START_TIME
|
||||
- _APP_DATABASE_SHARED_TABLES
|
||||
|
||||
appwrite-task-interval:
|
||||
entrypoint: interval
|
||||
<<: *x-logging
|
||||
container_name: appwrite-task-interval
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET_CNAME
|
||||
- _APP_DOMAIN_TARGET_AAAA
|
||||
- _APP_DOMAIN_TARGET_A
|
||||
- _APP_DOMAIN_TARGET_CAA
|
||||
- _APP_DNS
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_DATABASE_SHARED_TABLES
|
||||
- _APP_INTERVAL_DOMAIN_VERIFICATION
|
||||
|
||||
appwrite-task-stats-resources:
|
||||
container_name: appwrite-task-stats-resources
|
||||
entrypoint: stats-resources
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Change Log
|
||||
|
||||
## 13.0.0-rc.2
|
||||
|
||||
* Fixes a lot of typescript errors throughout the codebase
|
||||
|
||||
## 13.0.0-rc.1
|
||||
|
||||
* Migrates codebase from JavaScript to TypeScript
|
||||
|
||||
## 12.0.1
|
||||
|
||||
Fix type generation for `point`, `lineString` and `polygon` columns
|
||||
|
||||
@@ -8,6 +8,10 @@ interface Adapter
|
||||
{
|
||||
public function issueCertificate(string $certName, string $domain, ?string $domainType): ?string;
|
||||
|
||||
public function isInstantGeneration(string $domain, ?string $domainType): bool;
|
||||
|
||||
public function getCertificateStatus(string $domain, ?string $domainType): string;
|
||||
|
||||
public function isRenewRequired(string $domain, ?string $domainType, Log $log): bool;
|
||||
|
||||
public function deleteCertificate(string $domain): void;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Certificates\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
// Exception thrown during certificate status retrieval
|
||||
class CertificateStatus extends Exception
|
||||
{
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Appwrite\Certificates;
|
||||
|
||||
use Appwrite\Certificates\Exception\CertificateStatus as CertificateStatusException;
|
||||
use Exception;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
@@ -84,6 +85,16 @@ class LetsEncrypt implements Adapter
|
||||
return DateTime::addSeconds($dt, -60 * 60 * 24 * 30);
|
||||
}
|
||||
|
||||
public function isInstantGeneration(string $domain, ?string $domainType): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getCertificateStatus(string $domain, ?string $domainType): string
|
||||
{
|
||||
throw new CertificateStatusException('Certificate status retrieval is not supported for LetsEncrypt.');
|
||||
}
|
||||
|
||||
public function isRenewRequired(string $domain, ?string $domainType, Log $log): bool
|
||||
{
|
||||
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
|
||||
|
||||
@@ -8,7 +8,10 @@ use Utopia\System\System;
|
||||
|
||||
class Certificate extends Event
|
||||
{
|
||||
public const string ACTION_DOMAIN_VERIFICATION = 'verification';
|
||||
public const string ACTION_GENERATION = 'generation';
|
||||
protected bool $skipRenewCheck = false;
|
||||
protected string $action = self::ACTION_GENERATION;
|
||||
protected ?Document $domain = null;
|
||||
protected ?string $validationDomain = null;
|
||||
|
||||
@@ -91,6 +94,28 @@ class Certificate extends Event
|
||||
return $this->skipRenewCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set action for this certificate event.
|
||||
*
|
||||
* @param string $action
|
||||
* @return self
|
||||
*/
|
||||
public function setAction(string $action): self
|
||||
{
|
||||
$this->action = $action;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get action for this certificate event.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAction(): string
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the payload for the event
|
||||
@@ -103,7 +128,8 @@ class Certificate extends Event
|
||||
'project' => $this->project,
|
||||
'domain' => $this->domain,
|
||||
'skipRenewCheck' => $this->skipRenewCheck,
|
||||
'validationDomain' => $this->validationDomain
|
||||
'validationDomain' => $this->validationDomain,
|
||||
'action' => $this->action
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ class Action extends UtopiaAction
|
||||
protected mixed $logError;
|
||||
|
||||
protected array $filters = [
|
||||
'subQueryKeys', 'subQueryWebhooks', 'subQueryPlatforms', 'subQueryProjectVariables', 'subQueryBlocks', 'subQueryDevKeys', // Project
|
||||
'subQueryKeys', 'subQueryWebhooks', 'subQueryPlatforms', 'subQueryBlocks', 'subQueryDevKeys', // Project
|
||||
'subQueryAuthenticators', 'subQuerySessions', 'subQueryTokens', 'subQueryChallenges', 'subQueryMemberships', 'subQueryTargets', 'subQueryTopicTargets',// Users
|
||||
'subQueryVariables', // Sites
|
||||
'subQueryVariables', 'subQueryProjectVariables' // Sites / Functions
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
+5
-3
@@ -382,9 +382,11 @@ abstract class Action extends DatabasesAction
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
|
||||
$queueForWebhooks
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
if (!empty($queueForEvents->getProject()?->getAttribute('webhooks', []))) {
|
||||
$queueForWebhooks
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
$queueForEvents->reset();
|
||||
|
||||
+1
-1
@@ -227,7 +227,7 @@ class Create extends Action
|
||||
// Add permissions for current the user if none were provided.
|
||||
if (\is_null($permissions)) {
|
||||
$permissions = [];
|
||||
if (!empty($user->getId())) {
|
||||
if (!empty($user->getId()) && !$isPrivilegedUser) {
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$permissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Proxy\Http\Rules;
|
||||
namespace Appwrite\Platform\Modules\Proxy;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\DNS as ValidatorDNS;
|
||||
@@ -5,7 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\API;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Proxy\Http\Rules\Action;
|
||||
use Appwrite\Platform\Modules\Proxy\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
@@ -125,6 +125,7 @@ class Create extends Action
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->setAction(Certificate::ACTION_GENERATION)
|
||||
->trigger();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\Function;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Proxy\Http\Rules\Action;
|
||||
use Appwrite\Platform\Modules\Proxy\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
@@ -143,6 +143,7 @@ class Create extends Action
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->setAction(Certificate::ACTION_GENERATION)
|
||||
->trigger();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Appwrite\Platform\Modules\Proxy\Http\Rules;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Proxy\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\Redirect;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Proxy\Http\Rules\Action;
|
||||
use Appwrite\Platform\Modules\Proxy\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
@@ -147,6 +147,7 @@ class Create extends Action
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->setAction(Certificate::ACTION_GENERATION)
|
||||
->trigger();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\Site;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Proxy\Http\Rules\Action;
|
||||
use Appwrite\Platform\Modules\Proxy\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
@@ -143,6 +143,7 @@ class Create extends Action
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->setAction(Certificate::ACTION_GENERATION)
|
||||
->trigger();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\Verification;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Proxy\Http\Rules\Action;
|
||||
use Appwrite\Platform\Modules\Proxy\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Appwrite\Platform\Modules\Proxy\Http\Rules;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Proxy\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Appwrite\Platform\Services;
|
||||
|
||||
use Appwrite\Platform\Tasks\Doctor;
|
||||
use Appwrite\Platform\Tasks\Install;
|
||||
use Appwrite\Platform\Tasks\Interval;
|
||||
use Appwrite\Platform\Tasks\Maintenance;
|
||||
use Appwrite\Platform\Tasks\Migrate;
|
||||
use Appwrite\Platform\Tasks\QueueRetry;
|
||||
@@ -28,6 +29,7 @@ class Tasks extends Service
|
||||
$this
|
||||
->addAction(Doctor::getName(), new Doctor())
|
||||
->addAction(Install::getName(), new Install())
|
||||
->addAction(Interval::getName(), new Interval())
|
||||
->addAction(Maintenance::getName(), new Maintenance())
|
||||
->addAction(Migrate::getName(), new Migrate())
|
||||
->addAction(QueueRetry::getName(), new QueueRetry())
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Tasks;
|
||||
|
||||
use Appwrite\Event\Certificate;
|
||||
use DateTime;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime as DatabaseDateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Interval extends Action
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'interval';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->desc('Schedules tasks on regular intervals by publishing them to our queues')
|
||||
->inject('dbForPlatform')
|
||||
->inject('queueForCertificates')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(Database $dbForPlatform, Certificate $queueForCertificates): void
|
||||
{
|
||||
Console::title('Interval V1');
|
||||
Console::success(APP_NAME . ' interval process v1 has started');
|
||||
|
||||
$intervalDomainVerification = (int) System::getEnv('_APP_INTERVAL_DOMAIN_VERIFICATION', '60'); // 1 minute
|
||||
|
||||
\go(function () use ($dbForPlatform, $queueForCertificates, $intervalDomainVerification) {
|
||||
Console::loop(function () use ($dbForPlatform, $queueForCertificates) {
|
||||
$this->verifyDomain($dbForPlatform, $queueForCertificates);
|
||||
}, $intervalDomainVerification);
|
||||
});
|
||||
}
|
||||
|
||||
private function verifyDomain(Database $dbForPlatform, Certificate $queueForCertificates): void
|
||||
{
|
||||
$time = DatabaseDateTime::now();
|
||||
$fromTime = new DateTime('-3 days'); // Max 3 days old
|
||||
|
||||
$rules = $dbForPlatform->find('rules', [
|
||||
Query::createdAfter(DatabaseDateTime::format($fromTime)),
|
||||
Query::equal('status', [RULE_STATUS_CREATED]), // Created but not verified yet
|
||||
Query::orderAsc('$updatedAt'), // Pick the ones waiting for another attempt for longest
|
||||
Query::equal('region', [System::getEnv('_APP_REGION', 'default')]), // Only current region
|
||||
Query::limit(30), // Reasonable pagination limit, processable within a minute
|
||||
]);
|
||||
|
||||
if (\count($rules) === 0) {
|
||||
Console::info("[{$time}] No rules for domain verification.");
|
||||
return; // No rules to verify
|
||||
}
|
||||
|
||||
Console::info("[{$time}] Found " . \count($rules) . " rules for domain verification, scheduling jobs.");
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
$queueForCertificates
|
||||
->setDomain(new Document([
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->setAction(Certificate::ACTION_DOMAIN_VERIFICATION)
|
||||
->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,33 +125,36 @@ class Maintenance extends Action
|
||||
Query::limit(200), // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains)
|
||||
]);
|
||||
|
||||
if (\count($certificates) === 0) {
|
||||
Console::info("[{$time}] No certificates for renewal.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (\count($certificates) > 0) {
|
||||
Console::info("[{$time}] Found " . \count($certificates) . " certificates for renewal, scheduling jobs.");
|
||||
Console::info("[{$time}] Found " . \count($certificates) . " certificates for renewal, scheduling jobs.");
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$isMd5 = System::getEnv('_APP_RULES_FORMAT') === 'md5';
|
||||
$isMd5 = System::getEnv('_APP_RULES_FORMAT') === 'md5';
|
||||
$appRegion = System::getEnv('_APP_REGION', 'default');
|
||||
|
||||
foreach ($certificates as $certificate) {
|
||||
$domain = $certificate->getAttribute('domain');
|
||||
$rule = $isMd5
|
||||
? $dbForPlatform->getDocument('rules', md5($domain))
|
||||
: $dbForPlatform->findOne('rules', [
|
||||
foreach ($certificates as $certificate) {
|
||||
$domain = $certificate->getAttribute('domain');
|
||||
$rule = $isMd5 ?
|
||||
$dbForPlatform->getDocument('rules', md5($domain)) :
|
||||
$dbForPlatform->findOne('rules', [
|
||||
Query::equal('domain', [$domain]),
|
||||
Query::limit(1)
|
||||
]);
|
||||
|
||||
if ($rule->isEmpty() || $rule->getAttribute('region') !== System::getEnv('_APP_REGION', 'default')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$queueForCertificate
|
||||
->setDomain(new Document([
|
||||
'domain' => $certificate->getAttribute('domain')
|
||||
]))
|
||||
->trigger();
|
||||
if ($rule->isEmpty() || $rule->getAttribute('region') !== $appRegion) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
Console::info("[{$time}] No certificates for renewal.");
|
||||
|
||||
$queueForCertificate
|
||||
->setDomain(new Document([
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->setAction(Certificate::ACTION_GENERATION)
|
||||
->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ class SDKs extends Action
|
||||
return 'sdks';
|
||||
}
|
||||
|
||||
public static function getPlatforms(): array
|
||||
{
|
||||
return Specs::getPlatforms();
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
@@ -55,7 +60,7 @@ class SDKs extends Action
|
||||
public function action(?string $selectedPlatform, ?string $selectedSDK, ?string $version, ?string $git, ?string $production, ?string $message, ?string $release, ?string $commit, ?string $sdks): void
|
||||
{
|
||||
if (!$sdks) {
|
||||
$selectedPlatform ??= Console::confirm('Choose Platform ("' . implode('", "', Specs::getPlatforms()) . '" or "*" for all):');
|
||||
$selectedPlatform ??= Console::confirm('Choose Platform ("' . implode('", "', static::getPlatforms()) . '" or "*" for all):');
|
||||
$selectedSDK ??= \strtolower(Console::confirm('Choose SDK ("*" for all):'));
|
||||
} else {
|
||||
$sdks = explode(',', $sdks);
|
||||
@@ -188,8 +193,8 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
break;
|
||||
case 'php':
|
||||
$config = new PHP();
|
||||
$config->setComposerVendor('appwrite');
|
||||
$config->setComposerPackage('appwrite');
|
||||
$config->setComposerVendor($language['composerVendor'] ?? 'appwrite');
|
||||
$config->setComposerPackage($language['composerPackage'] ?? 'appwrite');
|
||||
break;
|
||||
case 'nodejs':
|
||||
$config = new Node();
|
||||
@@ -374,9 +379,9 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
|
||||
$sdk
|
||||
->setName($language['name'])
|
||||
->setNamespace('io appwrite')
|
||||
->setDescription("Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the {$language['name']} SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)")
|
||||
->setShortDescription('Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API')
|
||||
->setNamespace($language['namespace'] ?? 'appwrite')
|
||||
->setDescription($language['description'] ?? "Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the {$language['name']} SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)")
|
||||
->setShortDescription('Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API')
|
||||
->setLicense($license)
|
||||
->setLicenseContent($licenseContent)
|
||||
->setVersion($language['version'])
|
||||
|
||||
@@ -239,7 +239,7 @@ class Specs extends Action
|
||||
App::setResource('dbForPlatform', fn () => new Database(new MySQL(''), new Cache(new None())));
|
||||
App::setResource('dbForProject', fn () => new Database(new MySQL(''), new Cache(new None())));
|
||||
|
||||
$platforms = self::getPlatforms();
|
||||
$platforms = static::getPlatforms();
|
||||
$authCounts = $this->getAuthCounts();
|
||||
$keys = $this->getKeys();
|
||||
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
namespace Appwrite\Platform\Workers;
|
||||
|
||||
use Appwrite\Certificates\Adapter as CertificatesAdapter;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Realtime;
|
||||
use Appwrite\Event\Webhook;
|
||||
use Appwrite\Network\Validator\DNS;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Appwrite\Platform\Modules\Proxy\Action;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Response\Model\Rule;
|
||||
use Exception;
|
||||
@@ -22,15 +24,12 @@ use Utopia\Database\Exception\Conflict;
|
||||
use Utopia\Database\Exception\Structure;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Database\Validator\Authorization as ValidatorAuthorization;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Queue\Message;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\AnyOf;
|
||||
use Utopia\Validator\IP;
|
||||
|
||||
class Certificates extends Action
|
||||
{
|
||||
@@ -42,8 +41,10 @@ class Certificates extends Action
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(...$params)
|
||||
{
|
||||
parent::__construct(...$params);
|
||||
|
||||
$this
|
||||
->desc('Certificates worker')
|
||||
->inject('message')
|
||||
@@ -53,6 +54,7 @@ class Certificates extends Action
|
||||
->inject('queueForWebhooks')
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForRealtime')
|
||||
->inject('queueForCertificates')
|
||||
->inject('log')
|
||||
->inject('certificates')
|
||||
->inject('plan')
|
||||
@@ -67,6 +69,7 @@ class Certificates extends Action
|
||||
* @param Webhook $queueForWebhooks
|
||||
* @param Func $queueForFunctions
|
||||
* @param Realtime $queueForRealtime
|
||||
* @param Certificate $queueForCertificates
|
||||
* @param Log $log
|
||||
* @param CertificatesAdapter $certificates
|
||||
* @return void
|
||||
@@ -81,6 +84,7 @@ class Certificates extends Action
|
||||
Webhook $queueForWebhooks,
|
||||
Func $queueForFunctions,
|
||||
Realtime $queueForRealtime,
|
||||
Certificate $queueForCertificates,
|
||||
Log $log,
|
||||
CertificatesAdapter $certificates,
|
||||
array $plan
|
||||
@@ -93,14 +97,96 @@ class Certificates extends Action
|
||||
|
||||
$document = new Document($payload['domain'] ?? []);
|
||||
$domain = new Domain($document->getAttribute('domain', ''));
|
||||
$domainType = $document->getAttribute('domainType');
|
||||
$skipRenewCheck = $payload['skipRenewCheck'] ?? false;
|
||||
$validationDomain = $payload['validationDomain'] ?? null;
|
||||
$action = $payload['action'] ?? Certificate::ACTION_GENERATION;
|
||||
|
||||
$log->addTag('domain', $domain->get());
|
||||
|
||||
$domainType = $document->getAttribute('domainType');
|
||||
switch ($action) {
|
||||
case Certificate::ACTION_DOMAIN_VERIFICATION:
|
||||
$this->handleDomainVerificationAction($domain, $dbForPlatform, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $queueForCertificates, $log, $validationDomain);
|
||||
break;
|
||||
|
||||
$this->execute($domain, $domainType, $dbForPlatform, $queueForMails, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $log, $certificates, $skipRenewCheck, $plan, $validationDomain);
|
||||
case Certificate::ACTION_GENERATION:
|
||||
$this->handleCertificateGenerationAction($domain, $domainType, $dbForPlatform, $queueForMails, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $log, $certificates, $skipRenewCheck, $plan, $validationDomain);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Invalid action: ' . $action);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Domain $domain
|
||||
* @param Database $dbForPlatform
|
||||
* @param Event $queueForEvents
|
||||
* @param Webhook $queueForWebhooks
|
||||
* @param Func $queueForFunctions
|
||||
* @param Realtime $queueForRealtime
|
||||
* @param Certificate $queueForCertificates
|
||||
* @param Log $log
|
||||
* @param string|null $validationDomain
|
||||
* @return void
|
||||
* @throws Throwable
|
||||
* @throws \Utopia\Database\Exception
|
||||
*/
|
||||
private function handleDomainVerificationAction(
|
||||
Domain $domain,
|
||||
Database $dbForPlatform,
|
||||
Event $queueForEvents,
|
||||
Webhook $queueForWebhooks,
|
||||
Func $queueForFunctions,
|
||||
Realtime $queueForRealtime,
|
||||
Certificate $queueForCertificates,
|
||||
Log $log,
|
||||
?string $validationDomain = null
|
||||
): void {
|
||||
// Get rule
|
||||
$rule = System::getEnv('_APP_RULES_FORMAT') === 'md5'
|
||||
? ValidatorAuthorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($domain->get())))
|
||||
: ValidatorAuthorization::skip(fn () => $dbForPlatform->findOne('rules', [
|
||||
Query::equal('domain', [$domain->get()]),
|
||||
Query::limit(1),
|
||||
]));
|
||||
|
||||
// Skip if rule is not desired state (created but not verified yet).
|
||||
if ($rule->getAttribute('status', '') !== RULE_STATUS_CREATED) {
|
||||
Console::warning('Domain verification for ' . $rule->getAttribute('domain', '') . ' is not needed.');
|
||||
return;
|
||||
}
|
||||
|
||||
Console::info('Domain verification for ' . $rule->getAttribute('domain', '') . ' started.');
|
||||
|
||||
try {
|
||||
// Verify DNS records
|
||||
$this->validateDomain($rule, $domain, $log, $validationDomain);
|
||||
// Reset logs and status for the rule
|
||||
$rule->setAttribute('logs', '');
|
||||
$rule->setAttribute('status', RULE_STATUS_CERTIFICATE_GENERATING);
|
||||
|
||||
Console::success('Domain verification succeeded.');
|
||||
} catch (AppwriteException $err) {
|
||||
Console::warning('Domain verification failed: ' . $err->getMessage());
|
||||
$rule->setAttribute('logs', $err->getMessage());
|
||||
} finally {
|
||||
// Update rule and emit events
|
||||
$this->updateRuleAndSendEvents($rule, $dbForPlatform, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime);
|
||||
}
|
||||
|
||||
// Issue a TLS certificate when domain is verified
|
||||
if ($rule->getAttribute('status', '') === RULE_STATUS_CERTIFICATE_GENERATING) {
|
||||
$queueForCertificates
|
||||
->setDomain(new Document([
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->setAction(Certificate::ACTION_GENERATION)
|
||||
->trigger();
|
||||
|
||||
Console::success('Certificate generation triggered successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +205,7 @@ class Certificates extends Action
|
||||
* @throws Throwable
|
||||
* @throws \Utopia\Database\Exception
|
||||
*/
|
||||
private function execute(
|
||||
private function handleCertificateGenerationAction(
|
||||
Domain $domain,
|
||||
?string $domainType,
|
||||
Database $dbForPlatform,
|
||||
@@ -163,26 +249,42 @@ class Certificates extends Action
|
||||
* Note: Renewals are checked and scheduled from maintenance worker
|
||||
*/
|
||||
|
||||
// Get current certificate
|
||||
$certificate = $dbForPlatform->findOne('certificates', [Query::equal('domain', [$domain->get()])]);
|
||||
// Get rule document for domain
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$rule = System::getEnv('_APP_RULES_FORMAT') === 'md5'
|
||||
? ValidatorAuthorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($domain->get())))
|
||||
: ValidatorAuthorization::skip(fn () => $dbForPlatform->findOne('rules', [
|
||||
Query::equal('domain', [$domain->get()]),
|
||||
Query::limit(1),
|
||||
]));
|
||||
|
||||
// If we don't have certificate for domain yet, let's create new document. At the end we save it
|
||||
// Rule not found (or) not in the expected state
|
||||
if ($rule->isEmpty() || $rule->getAttribute('status') !== RULE_STATUS_CERTIFICATE_GENERATING) {
|
||||
Console::warning('Certificate generation for ' . $domain->get() . ' is skipped as the associated rule is either empty or not in the expected state.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get associated certificate for the rule
|
||||
$certificate = $dbForPlatform->getDocument('certificates', $rule->getAttribute('certificateId') ?? '');
|
||||
|
||||
// If we don't have certificate for the rule yet, let's create one.
|
||||
if ($certificate->isEmpty()) {
|
||||
$certificate = new Document();
|
||||
$certificate->setAttribute('domain', $domain->get());
|
||||
}
|
||||
|
||||
$success = false;
|
||||
|
||||
try {
|
||||
$date = \date('H:i:s');
|
||||
$certificate->setAttribute('logs', "\033[90m[{$date}] \033[97mCertificate generation started. \033[0m\n");
|
||||
|
||||
// Persist ASAP so that logs are reset in retry flow and user can see the latest logs on Console.
|
||||
$certificate = $this->upsertCertificate($rule, $certificate, $dbForPlatform);
|
||||
// Ensure certificate is associated with the rule
|
||||
$rule->setAttribute('certificateId', $certificate->getId());
|
||||
|
||||
// Validate domain and DNS records. Skip if job is forced
|
||||
if (!$skipRenewCheck) {
|
||||
$mainDomain = $validationDomain ?? $this->getMainDomain();
|
||||
$isMainDomain = !isset($mainDomain) || $domain->get() === $mainDomain;
|
||||
$this->validateDomain($domain, $isMainDomain, $log);
|
||||
$this->validateDomain($rule, $domain, $log, $validationDomain);
|
||||
|
||||
// If certificate exists already, double-check expiry date. Skip if job is forced
|
||||
if (!$certificates->isRenewRequired($domain->get(), $domainType, $log)) {
|
||||
@@ -191,85 +293,171 @@ class Certificates extends Action
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare unique cert name. Using this helps prevent miss-match in configuration when renewing certificates.
|
||||
// Prepare unique cert name. Using this helps prevent mismatch in configuration when renewing certificates.
|
||||
$certName = ID::unique();
|
||||
$renewDate = $certificates->issueCertificate($certName, $domain->get(), $domainType);
|
||||
|
||||
// Command succeeded, store all data into document
|
||||
$certificate->setAttribute('logs', 'Certificate successfully generated.');
|
||||
// If certificate is generated instantly, we can mark the rule as 'verified'.
|
||||
if ($certificates->isInstantGeneration($domain->get(), $domainType)) {
|
||||
$rule->setAttribute('status', RULE_STATUS_VERIFIED);
|
||||
$certificate->setAttribute('logs', 'Certificate successfully generated.');
|
||||
}
|
||||
|
||||
// Update certificate info stored in database
|
||||
$certificate->setAttribute('renewDate', $renewDate);
|
||||
$certificate->setAttribute('attempts', 0);
|
||||
$certificate->setAttribute('issueDate', DateTime::now());
|
||||
$success = true;
|
||||
$certificate->setAttributes([
|
||||
'attempts' => 0, // Reset attempts count
|
||||
'issueDate' => DateTime::now(), // Store current time as issue date
|
||||
'renewDate' => $renewDate,
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
$logs = $e->getMessage();
|
||||
$currentLogs = $certificate->getAttribute('logs', '');
|
||||
$date = \date('H:i:s');
|
||||
$errorMessage = "\033[90m[{$date}] \033[31mCertificate generation failed: \033[0m\n";
|
||||
|
||||
$certificate->setAttribute('logs', $currentLogs . $errorMessage . \mb_strcut($logs, 0, 500000));// Limit to 500kb
|
||||
$attempts = $certificate->getAttribute('attempts', 0) + 1; // Increase attempts count
|
||||
|
||||
// Increase attempts count
|
||||
$attempts = $certificate->getAttribute('attempts', 0) + 1;
|
||||
$certificate->setAttribute('attempts', $attempts);
|
||||
// Update attributes on certificate document
|
||||
$certificate->setAttributes([
|
||||
'logs' => $currentLogs . $errorMessage . \mb_strcut($logs, 0, 500000), // Limit to 500kb
|
||||
'attempts' => $attempts,
|
||||
'renewDate' => DateTime::now(), // Store current time as renew date to ensure another attempt in next maintenance cycle.
|
||||
]);
|
||||
|
||||
// Store current time as renew date to ensure another attempt in next maintenance cycle.
|
||||
$certificate->setAttribute('renewDate', DateTime::now());
|
||||
// Mark rule as 'unverified'
|
||||
$rule->setAttribute('status', RULE_STATUS_CERTIFICATE_GENERATION_FAILED);
|
||||
|
||||
// Send email to security email
|
||||
$this->notifyError($domain->get(), $e->getMessage(), $attempts, $queueForMails, $plan);
|
||||
|
||||
throw $e;
|
||||
} finally {
|
||||
// All actions result in new updatedAt date
|
||||
// All actions result in new 'updated' date
|
||||
$certificate->setAttribute('updated', DateTime::now());
|
||||
// Save certificate document to database
|
||||
$this->upsertCertificate($rule, $certificate, $dbForPlatform);
|
||||
|
||||
// Save all changes we made to certificate document into database
|
||||
$this->saveCertificateDocument($domain->get(), $certificate, $success, $dbForPlatform, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime);
|
||||
// Ensure certificate is associated with the rule
|
||||
$rule->setAttribute('certificateId', $certificate->getId());
|
||||
// Update rule and emit events
|
||||
$this->updateRuleAndSendEvents($rule, $dbForPlatform, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save certificate data into database.
|
||||
* Save certificate data to database.
|
||||
*
|
||||
* @param string $domain Domain name that certificate is for
|
||||
* @param Document $rule Rule associated with the domain
|
||||
* @param Document $certificate Certificate document that we need to save
|
||||
* @param bool $success
|
||||
* @param Database $dbForPlatform Database connection for console
|
||||
* @param Event $queueForEvents
|
||||
* @param Func $queueForFunctions
|
||||
* @param Realtime $queueForRealtime
|
||||
* @return void
|
||||
* @return Document
|
||||
* @throws \Utopia\Database\Exception
|
||||
* @throws Authorization
|
||||
* @throws Conflict
|
||||
* @throws Structure
|
||||
*/
|
||||
private function saveCertificateDocument(
|
||||
string $domain,
|
||||
private function upsertCertificate(
|
||||
Document $rule,
|
||||
Document $certificate,
|
||||
bool $success,
|
||||
Database $dbForPlatform,
|
||||
): Document {
|
||||
// Decide whether update (or) insert is needed
|
||||
$existingCertificate = $dbForPlatform->getDocument('certificates', $rule->getAttribute('certificateId') ?? '');
|
||||
|
||||
if ($existingCertificate->isEmpty()) {
|
||||
$certificate->removeAttribute('$sequence');
|
||||
$certificate = $dbForPlatform->createDocument('certificates', $certificate);
|
||||
} else {
|
||||
$certificate = new Document(\array_merge($existingCertificate->getArrayCopy(), $certificate->getArrayCopy()));
|
||||
$certificate = $dbForPlatform->updateDocument('certificates', $certificate->getId(), $certificate);
|
||||
}
|
||||
|
||||
return $certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all existing domain documents so they have relation to correct certificate document.
|
||||
* This solves issues:
|
||||
* - when adding a domain for which there is already a certificate
|
||||
* - when renew creates new document? It might?
|
||||
* - overall makes it more reliable
|
||||
*
|
||||
* @param Document $rule Rule document that is affected by new certificate
|
||||
* @param Database $dbForPlatform Database connection for console
|
||||
* @param Event $queueForEvents Event publisher for events
|
||||
* @param Webhook $queueForWebhooks Webhook publisher for webhooks
|
||||
* @param Func $queueForFunctions Function publisher for functions
|
||||
* @param Realtime $queueForRealtime Realtime publisher for realtime events
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function updateRuleAndSendEvents(
|
||||
Document $rule,
|
||||
Database $dbForPlatform,
|
||||
Event $queueForEvents,
|
||||
Webhook $queueForWebhooks,
|
||||
Func $queueForFunctions,
|
||||
Realtime $queueForRealtime
|
||||
): void {
|
||||
// Check if update or insert required
|
||||
$certificateDocument = $dbForPlatform->findOne('certificates', [Query::equal('domain', [$domain])]);
|
||||
if (!$certificateDocument->isEmpty()) {
|
||||
// Merge new data with current data
|
||||
$certificate = new Document(\array_merge($certificateDocument->getArrayCopy(), $certificate->getArrayCopy()));
|
||||
$certificate = $dbForPlatform->updateDocument('certificates', $certificate->getId(), $certificate);
|
||||
} else {
|
||||
$certificate->removeAttribute('$sequence');
|
||||
$certificate = $dbForPlatform->createDocument('certificates', $certificate);
|
||||
$rule = $dbForPlatform->updateDocument('rules', $rule->getId(), $rule);
|
||||
$projectId = $rule->getAttribute('projectId');
|
||||
|
||||
// Skip events for console project (triggered by auto-ssl generation for 1 click setups)
|
||||
if ($projectId === 'console') {
|
||||
return;
|
||||
}
|
||||
|
||||
$certificateId = $certificate->getId();
|
||||
$this->updateDomainDocuments($certificateId, $domain, $success, $dbForPlatform, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime);
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
if ($project->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ruleModel = new Rule();
|
||||
$queueForEvents
|
||||
->setProject($project)
|
||||
->setEvent('rules.[ruleId].update')
|
||||
->setParam('ruleId', $rule->getId())
|
||||
->setPayload($rule->getArrayCopy(array_keys($ruleModel->getRules())));
|
||||
|
||||
/** Trigger Webhook */
|
||||
$queueForWebhooks
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
|
||||
/** Trigger Functions */
|
||||
$queueForFunctions
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
|
||||
/** Trigger Realtime Events */
|
||||
$queueForRealtime
|
||||
->setSubscribers(['console', $projectId])
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal domain validation functionality to prevent unnecessary attempts. We check:
|
||||
* - Domain needs to be public and valid (prevents NFT domains that are not supported)
|
||||
* - Domain must have proper DNS record
|
||||
*
|
||||
* @param Document $rule Rule to validate
|
||||
* @param Domain $domain Domain to validate
|
||||
* @param Log $log Logger for adding metrics
|
||||
* @param string|null $validationDomain Override for main domain check
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function validateDomain(Document $rule, Domain $domain, Log $log, ?string $validationDomain = null): void
|
||||
{
|
||||
$mainDomain = $validationDomain ?? $this->getMainDomain();
|
||||
$isMainDomain = !isset($mainDomain) || $domain->get() === $mainDomain;
|
||||
if (!$isMainDomain) {
|
||||
$this->verifyRule($rule, $log);
|
||||
} else {
|
||||
// Main domain validation
|
||||
// TODO: Would be awesome to check A/AAAA record here. Maybe dry run?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,74 +476,7 @@ class Certificates extends Action
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal domain validation functionality to prevent unnecessary attempts. We check:
|
||||
* - Domain needs to be public and valid (prevents NFT domains that are not supported)
|
||||
* - Domain must have proper DNS record
|
||||
*
|
||||
* @param Domain $domain Domain which we validate
|
||||
* @param bool $isMainDomain In case of master domain, we look for different DNS configurations
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function validateDomain(Domain $domain, bool $isMainDomain, Log $log): void
|
||||
{
|
||||
if (empty($domain->get())) {
|
||||
throw new Exception('Missing certificate domain.');
|
||||
}
|
||||
|
||||
if (!$domain->isKnown() || $domain->isTest()) {
|
||||
throw new Exception('Unknown public suffix for domain.');
|
||||
}
|
||||
|
||||
if (!$isMainDomain) {
|
||||
$validationStart = \microtime(true);
|
||||
|
||||
$validators = [];
|
||||
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
|
||||
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
|
||||
$validators[] = new DNS($targetCNAME->get(), Record::TYPE_CNAME);
|
||||
}
|
||||
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), Record::TYPE_A);
|
||||
}
|
||||
if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), Record::TYPE_AAAA);
|
||||
}
|
||||
|
||||
// Validate if domain target is properly configured
|
||||
if (empty($validators)) {
|
||||
throw new Exception('At least one of domain targets environment variable must be configured.');
|
||||
}
|
||||
|
||||
// Verify domain with DNS records
|
||||
$validator = new AnyOf($validators, AnyOf::TYPE_STRING);
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
$log->addExtra('dnsTiming', \strval(\microtime(true) - $validationStart));
|
||||
$log->addTag('dnsDomain', $domain->get());
|
||||
throw new Exception('Failed to verify domain DNS records.');
|
||||
}
|
||||
|
||||
// Ensure CAA won't block certificate issuance
|
||||
if (!empty(System::getEnv('_APP_DOMAIN_TARGET_CAA', ''))) {
|
||||
$validationStart = \microtime(true);
|
||||
$validator = new DNS(System::getEnv('_APP_DOMAIN_TARGET_CAA', ''), Record::TYPE_CAA);
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
$log->addExtra('dnsTimingCaa', \strval(\microtime(true) - $validationStart));
|
||||
$log->addTag('dnsDomain', $domain->get());
|
||||
$error = $validator->getDescription();
|
||||
$log->addExtra('dnsResponse', \is_array($error) ? \json_encode($error) : \strval($error));
|
||||
throw new Exception('Failed to verify domain DNS records. CAA records do not allow Appwrite\'s certificate issuer.');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Main domain validation
|
||||
// TODO: Would be awesome to check A/AAAA record here. Maybe dry run?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to make sure information about error is delivered to admnistrator.
|
||||
* Method to make sure information about error is delivered to administrator.
|
||||
*
|
||||
* @param string $domain Domain that caused the error
|
||||
* @param string $errorMessage Verbose error message
|
||||
@@ -406,78 +527,4 @@ class Certificates extends Action
|
||||
->setRecipient(System::getEnv('_APP_EMAIL_CERTIFICATES', System::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS')))
|
||||
->trigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all existing domain documents so they have relation to correct certificate document.
|
||||
* This solved issues:
|
||||
* - when adding a domain for which there is already a certificate
|
||||
* - when renew creates new document? It might?
|
||||
* - overall makes it more reliable
|
||||
*
|
||||
* @param string $certificateId ID of a new or updated certificate document
|
||||
* @param string $domain Domain that is affected by new certificate
|
||||
* @param bool $success Was certificate generation successful?
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function updateDomainDocuments(
|
||||
string $certificateId,
|
||||
string $domain,
|
||||
bool $success,
|
||||
Database $dbForPlatform,
|
||||
Event $queueForEvents,
|
||||
Webhook $queueForWebhooks,
|
||||
Func $queueForFunctions,
|
||||
Realtime $queueForRealtime
|
||||
): void {
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$isMd5 = System::getEnv('_APP_RULES_FORMAT') === 'md5';
|
||||
$rule = $isMd5
|
||||
? $dbForPlatform->getDocument('rules', md5($domain))
|
||||
: $dbForPlatform->findOne('rules', [
|
||||
Query::equal('domain', [$domain]),
|
||||
]);
|
||||
|
||||
if (!$rule->isEmpty()) {
|
||||
$rule->setAttribute('certificateId', $certificateId);
|
||||
$rule->setAttribute('status', $success ? 'verified' : 'unverified');
|
||||
$dbForPlatform->updateDocument('rules', $rule->getId(), $rule);
|
||||
|
||||
$projectId = $rule->getAttribute('projectId');
|
||||
|
||||
// Skip events for console project (triggered by auto-ssl generation for 1 click setups)
|
||||
if ($projectId === 'console') {
|
||||
return;
|
||||
}
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ruleModel = new Rule();
|
||||
$queueForEvents
|
||||
->setProject($project)
|
||||
->setEvent('rules.[ruleId].update')
|
||||
->setParam('ruleId', $rule->getId())
|
||||
->setPayload($rule->getArrayCopy(array_keys($ruleModel->getRules())));
|
||||
|
||||
/** Trigger Webhook */
|
||||
$queueForWebhooks
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
|
||||
/** Trigger Functions */
|
||||
$queueForFunctions
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
|
||||
/** Trigger Realtime Events */
|
||||
$queueForRealtime
|
||||
->from($queueForEvents)
|
||||
->setSubscribers(['console', $projectId])
|
||||
->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,14 +122,16 @@ class Functions extends Action
|
||||
$log->addTag('type', $type);
|
||||
|
||||
if (!empty($events)) {
|
||||
$limit = 30;
|
||||
$sum = 30;
|
||||
$limit = 100;
|
||||
$sum = 100;
|
||||
$offset = 0;
|
||||
while ($sum >= $limit) {
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::select(['$id', 'events']), // Skip variables subqueries
|
||||
Query::contains('events', $events),
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
Query::orderAsc('name'),
|
||||
Query::orderAsc('$sequence'),
|
||||
]);
|
||||
|
||||
$sum = \count($functions);
|
||||
@@ -147,6 +149,11 @@ class Functions extends Action
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* get variables subqueries cached
|
||||
*/
|
||||
$function = $dbForProject->getDocument('functions', $function->getId());
|
||||
|
||||
Console::success('Iterating function: ' . $function->getAttribute('name'));
|
||||
|
||||
$this->execute(
|
||||
|
||||
@@ -192,13 +192,13 @@ class StatsResources extends Action
|
||||
}
|
||||
|
||||
try {
|
||||
$this->countForDatabase($dbForProject, $region);
|
||||
$dbForProject->skipFilters(fn () => $this->countForDatabase($dbForProject, $region), ['subQueryAttributes', 'subQueryIndexes']);
|
||||
} catch (Throwable $th) {
|
||||
call_user_func_array($this->logError, [$th, "StatsResources", "count_for_database_{$project->getId()}"]);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->countForSitesAndFunctions($dbForProject, $region);
|
||||
$dbForProject->skipFilters(fn () => $this->countForSitesAndFunctions($dbForProject, $region), ['subQueryVariables', 'subQueryProjectVariables']);
|
||||
} catch (Throwable $th) {
|
||||
call_user_func_array($this->logError, [$th, "StatsResources", "count_for_functions_{$project->getId()}"]);
|
||||
}
|
||||
|
||||
@@ -204,6 +204,8 @@ abstract class Format
|
||||
switch ($param) {
|
||||
case 'permissions':
|
||||
return 'BrowserPermission';
|
||||
case 'output':
|
||||
return 'ImageFormat';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1845,7 +1845,7 @@ class AccountCustomClientTest extends Scope
|
||||
]));
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertEquals(99, $response['headers']['x-ratelimit-remaining']);
|
||||
$this->assertEquals(119, $response['headers']['x-ratelimit-remaining']);
|
||||
$this->assertNotEmpty($response['body']['jwt']);
|
||||
$this->assertIsString($response['body']['jwt']);
|
||||
|
||||
|
||||
@@ -160,4 +160,40 @@ class StorageConsoleClientTest extends Scope
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testFilePermissionNotAutoSetInConsole(): void
|
||||
{
|
||||
// Create a bucket
|
||||
$bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'bucketId' => ID::unique(),
|
||||
'name' => 'Test Bucket Permissions',
|
||||
'fileSecurity' => true,
|
||||
]);
|
||||
$this->assertEquals(201, $bucket['headers']['status-code']);
|
||||
$bucketId = $bucket['body']['$id'];
|
||||
|
||||
// Create a file without providing permissions (console client should not auto-set permissions)
|
||||
$file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'fileId' => ID::unique(),
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'test.png'),
|
||||
]);
|
||||
$this->assertEquals(201, $file['headers']['status-code']);
|
||||
|
||||
// Verify file permissions are empty (not auto-set for privileged console user)
|
||||
$this->assertIsArray($file['body']['$permissions']);
|
||||
$this->assertEmpty($file['body']['$permissions']);
|
||||
|
||||
// Clean up: delete the bucket
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user