From 79c0368b58d56bdb2c8b802f305f023d41c2237e Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 17 Oct 2020 20:49:09 +0300 Subject: [PATCH 01/14] First commit --- app/controllers/api/account.php | 30 +++++ composer.json | 3 +- composer.lock | 215 ++++++++++++++++++++------------ 3 files changed, 166 insertions(+), 82 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index f80c09c6b9..9eaa82d5aa 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1,5 +1,6 @@ desc('Create Account JWT') + ->groups(['api', 'account']) + ->label('scope', 'account') + ->label('sdk.platform', [APP_PLATFORM_CLIENT]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'createJWT') + ->label('sdk.description', '/docs/references/account/create-jwt.md') + ->label('abuse-limit', 10) + ->label('abuse-key', 'url:{url},userId:{param-userId}') + ->action(function ($request, $response, $projectDB) { + /** @var Appwrite\Swoole\Request $request */ + /** @var Appwrite\Utopia\Response $response */ + /** @var Appwrite\Database\Database $projectDB */ + + // Instantiate with key, algo, maxAge and leeway. + $jwt = new JWT('secret', 'HS256', 3600, 10); + + $response->setStatusCode(Response::STATUS_CODE_CREATED); + + // $response->dynamic(new Document(['jwt' => $jwt]), Response::MODEL_SESSION); + $response->json(['jwt' => $jwt->encode([ + 'uid' => 1, + 'aud' => 'http://site.com', + 'scopes' => ['user'], + 'iss' => 'http://api.mysite.com', + ])]); + }, ['request', 'response', 'projectDB', 'webhooks', 'audits']); + App::get('/v1/account') ->desc('Get Account') ->groups(['api', 'account']) diff --git a/composer.json b/composer.json index f0ce2624cb..822258dcb3 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,8 @@ "domnikl/statsd": "3.0.*", "influxdb/influxdb-php": "1.15.*", "bacon/bacon-qr-code": "2.0.2", - "phpmailer/phpmailer": "6.1.7" + "phpmailer/phpmailer": "6.1.7", + "adhocore/jwt": "1.1.0" }, "require-dev": { "swoole/ide-helper": "4.5.4", diff --git a/composer.lock b/composer.lock index 297b144e81..31c4df00c6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,61 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "07a5b2d2e742e8651d58889c3253c3b5", + "content-hash": "20586cad26950d57c6fe42295d145904", "packages": [ + { + "name": "adhocore/jwt", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/adhocore/php-jwt.git", + "reference": "424a1d66b729a316dd074e6382167765b810cd3d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adhocore/php-jwt/zipball/424a1d66b729a316dd074e6382167765b810cd3d", + "reference": "424a1d66b729a316dd074e6382167765b810cd3d", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5 || ^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ahc\\Jwt\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jitendra Adhikari", + "email": "jiten.adhikary@gmail.com" + } + ], + "description": "Ultra lightweight JSON web token (JWT) library for PHP5.5+.", + "keywords": [ + "auth", + "json-web-token", + "jwt", + "jwt-auth", + "jwt-php", + "token" + ], + "funding": [ + { + "url": "https://paypal.me/ji10", + "type": "custom" + } + ], + "time": "2020-10-09T00:34:35+00:00" + }, { "name": "appwrite/php-clamav", "version": "v1.0.1", @@ -2300,12 +2353,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ece0c3ceee73810bd95226401bbfaea9e0f64de7" + "reference": "e33667ac376b7f4dbe97ab556f8e7c8daee383d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ece0c3ceee73810bd95226401bbfaea9e0f64de7", - "reference": "ece0c3ceee73810bd95226401bbfaea9e0f64de7", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e33667ac376b7f4dbe97ab556f8e7c8daee383d3", + "reference": "e33667ac376b7f4dbe97ab556f8e7c8daee383d3", "shasum": "" }, "require": { @@ -2365,7 +2418,7 @@ "type": "github" } ], - "time": "2020-10-09T14:34:55+00:00" + "time": "2020-10-15T05:14:52+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2373,12 +2426,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" + "reference": "8a1b0bfa74eba894f241e23261febb84c7ffbd8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/8a1b0bfa74eba894f241e23261febb84c7ffbd8d", + "reference": "8a1b0bfa74eba894f241e23261febb84c7ffbd8d", "shasum": "" }, "require": { @@ -2421,7 +2474,7 @@ "type": "github" } ], - "time": "2020-09-28T05:57:25+00:00" + "time": "2020-10-15T05:05:12+00:00" }, { "name": "phpunit/php-invoker", @@ -2429,12 +2482,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + "reference": "dcc4b2e39d6cb5ba5435a0177ebe947c0c0d05ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/dcc4b2e39d6cb5ba5435a0177ebe947c0c0d05ff", + "reference": "dcc4b2e39d6cb5ba5435a0177ebe947c0c0d05ff", "shasum": "" }, "require": { @@ -2480,7 +2533,7 @@ "type": "github" } ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2020-10-15T05:05:21+00:00" }, { "name": "phpunit/php-text-template", @@ -2488,12 +2541,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "18c887016e60e52477e54534956d7b47bc52cd84" + "reference": "0b11f04dcd54d149c3904cda577ea8ef8735e377" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/18c887016e60e52477e54534956d7b47bc52cd84", - "reference": "18c887016e60e52477e54534956d7b47bc52cd84", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0b11f04dcd54d149c3904cda577ea8ef8735e377", + "reference": "0b11f04dcd54d149c3904cda577ea8ef8735e377", "shasum": "" }, "require": { @@ -2535,7 +2588,7 @@ "type": "github" } ], - "time": "2020-09-28T06:03:05+00:00" + "time": "2020-10-15T05:06:00+00:00" }, { "name": "phpunit/php-timer", @@ -2543,12 +2596,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "c9ff14f493699e2f6adee9fd06a0245b276643b7" + "reference": "7fe57355ba7462b1cd940d93aa003660b4e6db20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/c9ff14f493699e2f6adee9fd06a0245b276643b7", - "reference": "c9ff14f493699e2f6adee9fd06a0245b276643b7", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/7fe57355ba7462b1cd940d93aa003660b4e6db20", + "reference": "7fe57355ba7462b1cd940d93aa003660b4e6db20", "shasum": "" }, "require": { @@ -2590,7 +2643,7 @@ "type": "github" } ], - "time": "2020-09-28T06:00:25+00:00" + "time": "2020-10-15T05:05:31+00:00" }, { "name": "phpunit/phpunit", @@ -2598,12 +2651,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "8b79c2a70ae855e582cef1ca63a849fe07bdb01d" + "reference": "b5c7b8a5d87f4e8947cdaee629a4a9a93e71faf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8b79c2a70ae855e582cef1ca63a849fe07bdb01d", - "reference": "8b79c2a70ae855e582cef1ca63a849fe07bdb01d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b5c7b8a5d87f4e8947cdaee629a4a9a93e71faf4", + "reference": "b5c7b8a5d87f4e8947cdaee629a4a9a93e71faf4", "shasum": "" }, "require": { @@ -2689,7 +2742,7 @@ "type": "github" } ], - "time": "2020-10-11T07:43:20+00:00" + "time": "2020-10-16T07:52:13+00:00" }, { "name": "sebastian/cli-parser", @@ -2697,12 +2750,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "bb13fcea306b784ef38fc1cda21c1395c233f4bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/bb13fcea306b784ef38fc1cda21c1395c233f4bc", + "reference": "bb13fcea306b784ef38fc1cda21c1395c233f4bc", "shasum": "" }, "require": { @@ -2741,7 +2794,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2020-10-15T05:19:54+00:00" }, { "name": "sebastian/code-unit", @@ -2749,12 +2802,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "59236be62b1bb9919e6d7f60b0b832dc05cef9ab" + "reference": "46a6ff3fabc0449fa17ca3ec485c44ab792f65c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/59236be62b1bb9919e6d7f60b0b832dc05cef9ab", - "reference": "59236be62b1bb9919e6d7f60b0b832dc05cef9ab", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/46a6ff3fabc0449fa17ca3ec485c44ab792f65c1", + "reference": "46a6ff3fabc0449fa17ca3ec485c44ab792f65c1", "shasum": "" }, "require": { @@ -2793,7 +2846,7 @@ "type": "github" } ], - "time": "2020-10-02T14:47:54+00:00" + "time": "2020-10-15T05:03:44+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -2801,12 +2854,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + "reference": "a801a24d7681090e8334c631b99181df063ea457" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/a801a24d7681090e8334c631b99181df063ea457", + "reference": "a801a24d7681090e8334c631b99181df063ea457", "shasum": "" }, "require": { @@ -2844,7 +2897,7 @@ "type": "github" } ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2020-10-15T05:03:53+00:00" }, { "name": "sebastian/comparator", @@ -2852,12 +2905,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "7a8ff306445707539c1a6397372a982a1ec55120" + "reference": "d43148f588efca5b5dd0c3d98da467f5aafdac6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/7a8ff306445707539c1a6397372a982a1ec55120", - "reference": "7a8ff306445707539c1a6397372a982a1ec55120", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/d43148f588efca5b5dd0c3d98da467f5aafdac6b", + "reference": "d43148f588efca5b5dd0c3d98da467f5aafdac6b", "shasum": "" }, "require": { @@ -2914,7 +2967,7 @@ "type": "github" } ], - "time": "2020-09-30T06:47:25+00:00" + "time": "2020-10-15T05:04:03+00:00" }, { "name": "sebastian/complexity", @@ -2922,12 +2975,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "ba8cc2da0c0bfbc813d03b56406734030c7f1eff" + "reference": "6d4cf3e8224f1e8527ab434b4ba902978af523db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ba8cc2da0c0bfbc813d03b56406734030c7f1eff", - "reference": "ba8cc2da0c0bfbc813d03b56406734030c7f1eff", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/6d4cf3e8224f1e8527ab434b4ba902978af523db", + "reference": "6d4cf3e8224f1e8527ab434b4ba902978af523db", "shasum": "" }, "require": { @@ -2967,7 +3020,7 @@ "type": "github" } ], - "time": "2020-09-28T06:05:03+00:00" + "time": "2020-10-15T05:06:11+00:00" }, { "name": "sebastian/diff", @@ -2975,12 +3028,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "e3ec6059b3fe483d42fbaf1fe6eefa201f7b4a6d" + "reference": "c25d82b5b776a3ba4e3b232a8688e969477444e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e3ec6059b3fe483d42fbaf1fe6eefa201f7b4a6d", - "reference": "e3ec6059b3fe483d42fbaf1fe6eefa201f7b4a6d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c25d82b5b776a3ba4e3b232a8688e969477444e0", + "reference": "c25d82b5b776a3ba4e3b232a8688e969477444e0", "shasum": "" }, "require": { @@ -3029,7 +3082,7 @@ "type": "github" } ], - "time": "2020-10-13T11:48:30+00:00" + "time": "2020-10-15T05:04:12+00:00" }, { "name": "sebastian/environment", @@ -3037,12 +3090,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + "reference": "40fcf803a36737ce1d2c46c489fb5d1ec2db45d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/40fcf803a36737ce1d2c46c489fb5d1ec2db45d4", + "reference": "40fcf803a36737ce1d2c46c489fb5d1ec2db45d4", "shasum": "" }, "require": { @@ -3088,7 +3141,7 @@ "type": "github" } ], - "time": "2020-09-28T05:52:38+00:00" + "time": "2020-10-15T05:04:22+00:00" }, { "name": "sebastian/exporter", @@ -3096,12 +3149,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "dbdc89af25883b35be6ddd4b88a8bc5d22bb819d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/dbdc89af25883b35be6ddd4b88a8bc5d22bb819d", + "reference": "dbdc89af25883b35be6ddd4b88a8bc5d22bb819d", "shasum": "" }, "require": { @@ -3161,7 +3214,7 @@ "type": "github" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2020-10-15T05:04:32+00:00" }, { "name": "sebastian/global-state", @@ -3169,12 +3222,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "ea779cb749a478b22a2564ac41cd7bda79c78dc7" + "reference": "3a606041b47fb201c1d62ae03078d0e8a62569a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ea779cb749a478b22a2564ac41cd7bda79c78dc7", - "reference": "ea779cb749a478b22a2564ac41cd7bda79c78dc7", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3a606041b47fb201c1d62ae03078d0e8a62569a6", + "reference": "3a606041b47fb201c1d62ae03078d0e8a62569a6", "shasum": "" }, "require": { @@ -3221,7 +3274,7 @@ "type": "github" } ], - "time": "2020-09-28T05:54:06+00:00" + "time": "2020-10-15T05:04:42+00:00" }, { "name": "sebastian/lines-of-code", @@ -3229,12 +3282,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "6514b8f21906b8b46f520d1fbd17a4523fa59a54" + "reference": "5835b6f4707e022ae53a2a67420a3388b318715a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/6514b8f21906b8b46f520d1fbd17a4523fa59a54", - "reference": "6514b8f21906b8b46f520d1fbd17a4523fa59a54", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/5835b6f4707e022ae53a2a67420a3388b318715a", + "reference": "5835b6f4707e022ae53a2a67420a3388b318715a", "shasum": "" }, "require": { @@ -3274,7 +3327,7 @@ "type": "github" } ], - "time": "2020-09-28T06:07:27+00:00" + "time": "2020-10-15T05:06:21+00:00" }, { "name": "sebastian/object-enumerator", @@ -3282,12 +3335,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "f6f5957013d84725427d361507e13513702888a4" + "reference": "192362c78b33b0231e1e8841678be93ce6f31830" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f6f5957013d84725427d361507e13513702888a4", - "reference": "f6f5957013d84725427d361507e13513702888a4", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/192362c78b33b0231e1e8841678be93ce6f31830", + "reference": "192362c78b33b0231e1e8841678be93ce6f31830", "shasum": "" }, "require": { @@ -3327,7 +3380,7 @@ "type": "github" } ], - "time": "2020-09-28T05:55:06+00:00" + "time": "2020-10-15T05:04:51+00:00" }, { "name": "sebastian/object-reflector", @@ -3335,12 +3388,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "d9d0ab3b12acb1768bc1e0a89b23c90d2043cbe5" + "reference": "da3d1ade6fef132f2486d297c35cf61e45930a0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/d9d0ab3b12acb1768bc1e0a89b23c90d2043cbe5", - "reference": "d9d0ab3b12acb1768bc1e0a89b23c90d2043cbe5", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/da3d1ade6fef132f2486d297c35cf61e45930a0b", + "reference": "da3d1ade6fef132f2486d297c35cf61e45930a0b", "shasum": "" }, "require": { @@ -3378,7 +3431,7 @@ "type": "github" } ], - "time": "2020-09-28T05:56:16+00:00" + "time": "2020-10-15T05:05:01+00:00" }, { "name": "sebastian/recursion-context", @@ -3386,12 +3439,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "7e70f3d32a3058d4ad5226c1371f2dd4677dc073" + "reference": "3767a68ada0fc1d50b22db067cd2256b1b722faa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/7e70f3d32a3058d4ad5226c1371f2dd4677dc073", - "reference": "7e70f3d32a3058d4ad5226c1371f2dd4677dc073", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3767a68ada0fc1d50b22db067cd2256b1b722faa", + "reference": "3767a68ada0fc1d50b22db067cd2256b1b722faa", "shasum": "" }, "require": { @@ -3437,7 +3490,7 @@ "type": "github" } ], - "time": "2020-09-28T05:27:00+00:00" + "time": "2020-10-15T05:05:41+00:00" }, { "name": "sebastian/resource-operations", @@ -3496,12 +3549,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "fa592377f3923946cb90bf1f6a71ba2e5f229909" + "reference": "5eb6a85e349cab8a411886cb52c070393d71bc7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fa592377f3923946cb90bf1f6a71ba2e5f229909", - "reference": "fa592377f3923946cb90bf1f6a71ba2e5f229909", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/5eb6a85e349cab8a411886cb52c070393d71bc7e", + "reference": "5eb6a85e349cab8a411886cb52c070393d71bc7e", "shasum": "" }, "require": { @@ -3540,7 +3593,7 @@ "type": "github" } ], - "time": "2020-10-06T08:41:03+00:00" + "time": "2020-10-15T05:05:50+00:00" }, { "name": "sebastian/version", From 8c4f3f7f9d092a2c4c78560c18b266ed2b843d72 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 18:41:03 +0200 Subject: [PATCH 02/14] New JWT model --- src/Appwrite/Utopia/Response/Model/JWT.php | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/Appwrite/Utopia/Response/Model/JWT.php diff --git a/src/Appwrite/Utopia/Response/Model/JWT.php b/src/Appwrite/Utopia/Response/Model/JWT.php new file mode 100644 index 0000000000..490506ff94 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/JWT.php @@ -0,0 +1,45 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'User ID.', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'User name.', + 'example' => 'John Doe', + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'JWT'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_JWT; + } +} \ No newline at end of file From 98a7f6a1050bdb37473722b478e2300d5fd0b28a Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 18:41:32 +0200 Subject: [PATCH 03/14] Added JWT library --- composer.json | 3 +- composer.lock | 88 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/composer.json b/composer.json index afefca980b..fa5b69af0a 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,8 @@ "domnikl/statsd": "3.0.2", "influxdb/influxdb-php": "1.15.1", "phpmailer/phpmailer": "6.1.7", - "chillerlan/php-qrcode": "4.2.0" + "chillerlan/php-qrcode": "4.2.0", + "adhocore/jwt": "1.1.0" }, "require-dev": { "swoole/ide-helper": "4.5.5", diff --git a/composer.lock b/composer.lock index 73123ca30d..671c357e53 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "aa1bf812ee6a45af12cdfbbfb7229471", + "content-hash": "518aa516713cbed3cad684907d50aea1", "packages": [ { "name": "adhocore/jwt", @@ -51,6 +51,10 @@ "jwt-php", "token" ], + "support": { + "issues": "https://github.com/adhocore/php-jwt/issues", + "source": "https://github.com/adhocore/php-jwt/tree/1.1.0" + }, "funding": [ { "url": "https://paypal.me/ji10", @@ -1953,12 +1957,12 @@ "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "64291c788b9a18272346decf566931e33a317399" + "reference": "f921205948ab93bb19f86327c793a81edb62f236" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/64291c788b9a18272346decf566931e33a317399", - "reference": "64291c788b9a18272346decf566931e33a317399", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/f921205948ab93bb19f86327c793a81edb62f236", + "reference": "f921205948ab93bb19f86327c793a81edb62f236", "shasum": "" }, "require": { @@ -2019,7 +2023,7 @@ "type": "tidelift" } ], - "time": "2020-11-12T09:39:33+00:00" + "time": "2020-12-27T20:11:05+00:00" }, { "name": "composer/semver", @@ -2376,16 +2380,16 @@ }, { "name": "matthiasmullie/minify", - "version": "1.3.64", + "version": "1.3.65", "source": { "type": "git", "url": "https://github.com/matthiasmullie/minify.git", - "reference": "38f9d58c739687e269f46c6dff4647de9e2eb855" + "reference": "227f19062451c55a797e0cc667ef983834e6580c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/38f9d58c739687e269f46c6dff4647de9e2eb855", - "reference": "38f9d58c739687e269f46c6dff4647de9e2eb855", + "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/227f19062451c55a797e0cc667ef983834e6580c", + "reference": "227f19062451c55a797e0cc667ef983834e6580c", "shasum": "" }, "require": { @@ -2434,9 +2438,23 @@ ], "support": { "issues": "https://github.com/matthiasmullie/minify/issues", - "source": "https://github.com/matthiasmullie/minify/tree/1.3.64" + "source": "https://github.com/matthiasmullie/minify/tree/1.3.65" }, - "time": "2020-12-23T13:37:53+00:00" + "funding": [ + { + "url": "https://github.com/[user1", + "type": "github" + }, + { + "url": "https://github.com/matthiasmullie] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g.", + "type": "github" + }, + { + "url": "https://github.com/user2", + "type": "github" + } + ], + "time": "2020-12-27T21:43:29+00:00" }, { "name": "matthiasmullie/path-converter", @@ -4552,12 +4570,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "15c96194f32e1b1aa30d1b302c71c5f83fd4dea9" + "reference": "c249efc71000d42c86d9a7558b55f409f06d93da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/15c96194f32e1b1aa30d1b302c71c5f83fd4dea9", - "reference": "15c96194f32e1b1aa30d1b302c71c5f83fd4dea9", + "url": "https://api.github.com/repos/symfony/console/zipball/c249efc71000d42c86d9a7558b55f409f06d93da", + "reference": "c249efc71000d42c86d9a7558b55f409f06d93da", "shasum": "" }, "require": { @@ -4642,7 +4660,7 @@ "type": "tidelift" } ], - "time": "2020-12-18T08:03:24+00:00" + "time": "2020-12-27T13:21:48+00:00" }, { "name": "symfony/polyfill-ctype", @@ -4650,12 +4668,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "fade6deebd931cfd7a544f68479405a6a08979a3" + "reference": "7130f348df2f842044038aaae9d6653dc9d67649" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fade6deebd931cfd7a544f68479405a6a08979a3", - "reference": "fade6deebd931cfd7a544f68479405a6a08979a3", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7130f348df2f842044038aaae9d6653dc9d67649", + "reference": "7130f348df2f842044038aaae9d6653dc9d67649", "shasum": "" }, "require": { @@ -4722,7 +4740,7 @@ "type": "tidelift" } ], - "time": "2020-10-26T13:35:45+00:00" + "time": "2020-12-27T09:28:48+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -4730,12 +4748,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "be092746c3ab9f9c62608c82e0f04687f8a879f9" + "reference": "e314d4992832c3a0a68ca731fadd959917320fda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/be092746c3ab9f9c62608c82e0f04687f8a879f9", - "reference": "be092746c3ab9f9c62608c82e0f04687f8a879f9", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e314d4992832c3a0a68ca731fadd959917320fda", + "reference": "e314d4992832c3a0a68ca731fadd959917320fda", "shasum": "" }, "require": { @@ -4804,7 +4822,7 @@ "type": "tidelift" } ], - "time": "2020-11-13T15:40:22+00:00" + "time": "2020-12-27T09:28:48+00:00" }, { "name": "symfony/polyfill-intl-normalizer", @@ -4812,12 +4830,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "69609f9f06790591b4b13a45ee117e7bab6395aa" + "reference": "3a79a2226897adae0cab81688fbc5144e2fc53f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/69609f9f06790591b4b13a45ee117e7bab6395aa", - "reference": "69609f9f06790591b4b13a45ee117e7bab6395aa", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3a79a2226897adae0cab81688fbc5144e2fc53f6", + "reference": "3a79a2226897adae0cab81688fbc5144e2fc53f6", "shasum": "" }, "require": { @@ -4889,7 +4907,7 @@ "type": "tidelift" } ], - "time": "2020-10-26T13:35:45+00:00" + "time": "2020-12-27T22:11:44+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -4897,12 +4915,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "401c9d9d3400c53a8f1a39425f0543406c137a43" + "reference": "de14691dc88bbbc5535de7f0e32080977dc1d23f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/401c9d9d3400c53a8f1a39425f0543406c137a43", - "reference": "401c9d9d3400c53a8f1a39425f0543406c137a43", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/de14691dc88bbbc5535de7f0e32080977dc1d23f", + "reference": "de14691dc88bbbc5535de7f0e32080977dc1d23f", "shasum": "" }, "require": { @@ -4970,7 +4988,7 @@ "type": "tidelift" } ], - "time": "2020-10-26T13:35:45+00:00" + "time": "2020-12-27T09:28:48+00:00" }, { "name": "symfony/polyfill-php73", @@ -5058,12 +5076,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "3a11f3dfb34ad50f978cb2b8cf936933b87739aa" + "reference": "54cc82c30ba7ed02bc64f5d010488c159b5f1706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/3a11f3dfb34ad50f978cb2b8cf936933b87739aa", - "reference": "3a11f3dfb34ad50f978cb2b8cf936933b87739aa", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/54cc82c30ba7ed02bc64f5d010488c159b5f1706", + "reference": "54cc82c30ba7ed02bc64f5d010488c159b5f1706", "shasum": "" }, "require": { @@ -5134,7 +5152,7 @@ "type": "tidelift" } ], - "time": "2020-10-26T13:35:45+00:00" + "time": "2020-12-27T09:28:48+00:00" }, { "name": "symfony/service-contracts", From 3caea2a62ca81284c90ef9b920d97dfde431e8f3 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 18:41:38 +0200 Subject: [PATCH 04/14] New JWT model --- src/Appwrite/Utopia/Response.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index a854416c3f..0db6990c88 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -20,6 +20,7 @@ use Appwrite\Utopia\Response\Model\ErrorDev; use Appwrite\Utopia\Response\Model\Execution; use Appwrite\Utopia\Response\Model\File; use Appwrite\Utopia\Response\Model\Func; +use Appwrite\Utopia\Response\Model\JWT; use Appwrite\Utopia\Response\Model\Key; use Appwrite\Utopia\Response\Model\Language; use Appwrite\Utopia\Response\Model\User; @@ -64,7 +65,8 @@ class Response extends SwooleResponse const MODEL_USER_LIST = 'userList'; const MODEL_SESSION = 'session'; const MODEL_SESSION_LIST = 'sessionList'; - const MODEL_TOKEN = 'token'; // - Missing + const MODEL_TOKEN = 'token'; + const MODEL_JWT = 'jwt'; // Storage const MODEL_FILE = 'file'; @@ -161,6 +163,7 @@ class Response extends SwooleResponse ->setModel(new User()) ->setModel(new Session()) ->setModel(new Token()) + ->setModel(new JWT()) ->setModel(new Locale()) ->setModel(new File()) ->setModel(new Team()) From f6d30fa1fb793b91ebfc1b40a33d619a884b5b4c Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 19:03:27 +0200 Subject: [PATCH 05/14] Added a new JWT endpoint --- app/controllers/api/account.php | 44 ++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 93ba7b397b..2b36908ed9 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -648,24 +648,38 @@ App::get('/v1/account/jwt') ->label('sdk.description', '/docs/references/account/create-jwt.md') ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},userId:{param-userId}') - ->action(function ($request, $response, $projectDB) { - /** @var Appwrite\Swoole\Request $request */ + ->inject('response') + ->inject('user') + ->action(function ($response, $user) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ - - // Instantiate with key, algo, maxAge and leeway. - $jwt = new JWT('secret', 'HS256', 3600, 10); + /** @var Appwrite\Database\Document $user */ + + $tokens = $user->getAttribute('tokens', []); + $session = new Document(); - $response->setStatusCode(Response::STATUS_CODE_CREATED); + foreach ($tokens as $token) { /** @var Appwrite\Database\Document $token */ + if ($token->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too + $session = $token; + } + } + + if($session->isEmpty()) { + throw new Exception('No valid session found', 401); + } - // $response->dynamic(new Document(['jwt' => $jwt]), Response::MODEL_SESSION); - $response->json(['jwt' => $jwt->encode([ - 'uid' => 1, - 'aud' => 'http://site.com', - 'scopes' => ['user'], - 'iss' => 'http://api.mysite.com', - ])]); - }, ['request', 'response', 'projectDB', 'webhooks', 'audits']); + $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 10); // Instantiate with key, algo, maxAge and leeway. + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic(new Document(['jwt' => $jwt->encode([ + // 'uid' => 1, + // 'aud' => 'http://site.com', + // 'scopes' => ['user'], + // 'iss' => 'http://api.mysite.com', + 'userId' => $user->getId(), + 'sessionId' => $session->getId(), + ])]), Response::MODEL_JWT); + }); App::get('/v1/account') ->desc('Get Account') From 40d735881c8f134fa22a7fa675dc635e1dbda9b1 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 19:03:47 +0200 Subject: [PATCH 06/14] JWT auth - work in progress --- app/controllers/general.php | 48 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index ce1d6cfbe2..31e39712f7 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -2,6 +2,7 @@ require_once __DIR__.'/../init.php'; +use Ahc\Jwt\JWT; use Utopia\App; use Utopia\Swoole\Request; use Appwrite\Utopia\Response; @@ -34,7 +35,6 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo /** @var Appwrite\Event\Event $usage */ /** @var Appwrite\Event\Event $deletes */ /** @var Appwrite\Event\Event $functions */ - /** @var bool $mode */ /** @var array $clients */ @@ -111,7 +111,6 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo $response ->addHeader('Server', 'Appwrite') ->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url='.\urlencode($request->getURI())) - //->addHeader('X-Frame-Options', ($refDomain == 'http://localhost') ? 'SAMEORIGIN' : 'ALLOW-FROM ' . $refDomain) ->addHeader('X-Content-Type-Options', 'nosniff') ->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE') ->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-SDK-Version, Cache-Control, Expires, Pragma') @@ -162,29 +161,38 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo $roles = Config::getParam('roles', []); $scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route $scopes = $roles[$role]['scopes']; // Allowed scopes for user role + $authKey = $request->getHeader('x-appwrite-key', ''); + $authJWT = $request->getHeader('x-appwrite-jwt', ''); - // Check if given key match project API keys - $key = $project->search('secret', $request->getHeader('x-appwrite-key', ''), $project->getAttribute('keys', [])); - - /* - * Try app auth when we have project key and no user - * Mock user to app and grant API key scopes in addition to default app scopes - */ - if (null !== $key && $user->isEmpty()) { - $user = new Document([ - '$id' => '', - 'status' => Auth::USER_STATUS_ACTIVATED, - 'email' => 'app.'.$project->getId().'@service.'.$request->getHostname(), - 'password' => '', - 'name' => $project->getAttribute('name', 'Untitled'), - ]); + if (!empty($authKey)) { // API Key authentication + // Check if given key match project API keys + $key = $project->search('secret', $authKey, $project->getAttribute('keys', [])); + + /* + * Try app auth when we have project key and no user + * Mock user to app and grant API key scopes in addition to default app scopes + */ + if (null !== $key && $user->isEmpty()) { + $user = new Document([ + '$id' => '', + 'status' => Auth::USER_STATUS_ACTIVATED, + 'email' => 'app.'.$project->getId().'@service.'.$request->getHostname(), + 'password' => '', + 'name' => $project->getAttribute('name', 'Untitled'), + ]); - $role = Auth::USER_ROLE_APP; - $scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', [])); + $role = Auth::USER_ROLE_APP; + $scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', [])); - Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys. + Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys. + } } + if (!empty($authJWT)) { // JWT authentication + $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 10); // Instantiate with key, algo, maxAge and leeway. + $payload = $jwt->decode($authJWT); + } + if ($user->getId()) { Authorization::setRole('user:'.$user->getId()); } From 002361c3b8db617247fef15cbf960649733f3154 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 22:18:07 +0200 Subject: [PATCH 07/14] Updated model structure --- src/Appwrite/Utopia/Response/Model/JWT.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/JWT.php b/src/Appwrite/Utopia/Response/Model/JWT.php index 490506ff94..67aa0f4d36 100644 --- a/src/Appwrite/Utopia/Response/Model/JWT.php +++ b/src/Appwrite/Utopia/Response/Model/JWT.php @@ -10,15 +10,10 @@ class JWT extends Model public function __construct() { $this - ->addRule('$id', [ + ->addRule('jwt', [ 'type' => self::TYPE_STRING, - 'description' => 'User ID.', - 'example' => '5e5ea5c16897e', - ]) - ->addRule('name', [ - 'type' => self::TYPE_STRING, - 'description' => 'User name.', - 'example' => 'John Doe', + 'description' => 'JWT encoded string.', + 'example' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', ]) ; } From 5e4619b6e0bdcf58f5db4ae83b1377c009afc6fa Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 22:31:42 +0200 Subject: [PATCH 08/14] Updated auth check --- app/controllers/general.php | 10 ++-------- app/init.php | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index 31e39712f7..5f9301aec1 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -2,7 +2,6 @@ require_once __DIR__.'/../init.php'; -use Ahc\Jwt\JWT; use Utopia\App; use Utopia\Swoole\Request; use Appwrite\Utopia\Response; @@ -161,9 +160,9 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo $roles = Config::getParam('roles', []); $scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route $scopes = $roles[$role]['scopes']; // Allowed scopes for user role + $authKey = $request->getHeader('x-appwrite-key', ''); - $authJWT = $request->getHeader('x-appwrite-jwt', ''); - + if (!empty($authKey)) { // API Key authentication // Check if given key match project API keys $key = $project->search('secret', $authKey, $project->getAttribute('keys', [])); @@ -188,11 +187,6 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo } } - if (!empty($authJWT)) { // JWT authentication - $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 10); // Instantiate with key, algo, maxAge and leeway. - $payload = $jwt->decode($authJWT); - } - if ($user->getId()) { Authorization::setRole('user:'.$user->getId()); } diff --git a/app/init.php b/app/init.php index 34ef3a5823..ad50ce17b5 100644 --- a/app/init.php +++ b/app/init.php @@ -11,6 +11,8 @@ if (\file_exists(__DIR__.'/../vendor/autoload.php')) { require_once __DIR__.'/../vendor/autoload.php'; } +use Ahc\Jwt\JWT; +use Ahc\Jwt\JWTException; use Appwrite\Auth\Auth; use Appwrite\Database\Database; use Appwrite\Database\Adapter\MySQL as MySQLAdapter; @@ -400,6 +402,29 @@ App::setResource('user', function($mode, $project, $console, $request, $response } } + $authJWT = $request->getHeader('x-appwrite-jwt', ''); + + if (!empty($authJWT)) { // JWT authentication + $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 10); // Instantiate with key, algo, maxAge and leeway. + + try { + $payload = $jwt->decode($authJWT); + } catch (JWTException $error) { + throw new Exception('Failed to verify JWT. '.$error->getMessage(), 401); + } + + $jwtUserId = $payload['userId'] ?? ''; + $jwtSessionId = $payload['sessionId'] ?? ''; + + if($jwtUserId && $jwtSessionId) { + $user = $projectDB->getDocument($jwtUserId); + } + + if (empty($user->search('$id', $jwtSessionId, $user->getAttribute('tokens')))) { // Match JWT to active token + $user = new Document(['$id' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]); + } + } + return $user; }, ['mode', 'project', 'console', 'request', 'response', 'projectDB', 'consoleDB']); From e4e0c23968cc3c98c89c27723407afcd15e02d85 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 22:31:55 +0200 Subject: [PATCH 09/14] Added tests --- app/controllers/api/account.php | 2 +- .../Account/AccountCustomClientTest.php | 98 +++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 2b36908ed9..35d41530e1 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -638,7 +638,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ; }); -App::get('/v1/account/jwt') +App::post('/v1/account/jwt') ->desc('Create Account JWT') ->groups(['api', 'account']) ->label('scope', 'account') diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 0e17d8fcc9..a111655307 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -128,4 +128,102 @@ class AccountCustomClientTest extends Scope return []; } + + public function testCreateJWT():array + { + $email = uniqid().'user@localhost.test'; + $password = 'password'; + $name = 'User Name (JWT)'; + + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'email' => $email, + 'password' => $password, + 'name' => $name, + ]); + + $id = $response['body']['$id']; + + $this->assertEquals($response['headers']['status-code'], 201); + + $response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'email' => $email, + 'password' => $password, + ]); + + $this->assertEquals($response['headers']['status-code'], 201); + + $sessionId = $response['body']['$id']; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + + $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session, + ])); + + $this->assertEquals($response['headers']['status-code'], 200); + + $response = $this->client->call(Client::METHOD_POST, '/account/jwt', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session, + ])); + + $this->assertEquals($response['headers']['status-code'], 201); + $this->assertNotEmpty($response['body']['jwt']); + $this->assertIsString($response['body']['jwt']); + + $jwt = $response['body']['jwt']; + + $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-jwt' => 'wrong-token', + ])); + + $this->assertEquals($response['headers']['status-code'], 401); + + $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-jwt' => $jwt, + ])); + + $this->assertEquals($response['headers']['status-code'], 200); + + $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionId, array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session, + ])); + + $this->assertEquals($response['headers']['status-code'], 204); + + $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-jwt' => $jwt, + ])); + + $this->assertEquals($response['headers']['status-code'], 401); + + return []; + } } \ No newline at end of file From bb52478bc3d2411c20306ef025694a1b65c914d2 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 23:23:09 +0200 Subject: [PATCH 10/14] Changed JWT expiry to max 15 minutes --- app/controllers/api/account.php | 2 +- app/init.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 35d41530e1..559024ba33 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -667,7 +667,7 @@ App::post('/v1/account/jwt') throw new Exception('No valid session found', 401); } - $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 10); // Instantiate with key, algo, maxAge and leeway. + $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. $response ->setStatusCode(Response::STATUS_CODE_CREATED) diff --git a/app/init.php b/app/init.php index ad50ce17b5..795e6c6664 100644 --- a/app/init.php +++ b/app/init.php @@ -405,8 +405,8 @@ App::setResource('user', function($mode, $project, $console, $request, $response $authJWT = $request->getHeader('x-appwrite-jwt', ''); if (!empty($authJWT)) { // JWT authentication - $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 10); // Instantiate with key, algo, maxAge and leeway. - + $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. + try { $payload = $jwt->decode($authJWT); } catch (JWTException $error) { From 94c23cd0532776fd2b09d3e4cf201f29c4204539 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 28 Dec 2020 23:23:18 +0200 Subject: [PATCH 11/14] Added docs --- docs/references/account/create-jwt.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/references/account/create-jwt.md diff --git a/docs/references/account/create-jwt.md b/docs/references/account/create-jwt.md new file mode 100644 index 0000000000..c606222eb5 --- /dev/null +++ b/docs/references/account/create-jwt.md @@ -0,0 +1 @@ +Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout. \ No newline at end of file From 328d3bcfd474452b2f2a42d7d3e6785be7bb2f1c Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Tue, 29 Dec 2020 12:45:44 +0200 Subject: [PATCH 12/14] Comments review --- app/controllers/general.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index 5f9301aec1..10681d33bb 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -171,7 +171,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo * Try app auth when we have project key and no user * Mock user to app and grant API key scopes in addition to default app scopes */ - if (null !== $key && $user->isEmpty()) { + if ($key && $user->isEmpty()) { $user = new Document([ '$id' => '', 'status' => Auth::USER_STATUS_ACTIVATED, From defc91ecf45068a76568394c8c309a6bae9e9c21 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Fri, 15 Jan 2021 00:33:41 +0200 Subject: [PATCH 13/14] Fix CI --- .travis.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index c395a2d73c..6d87d519ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,20 +13,20 @@ services: - docker before_install: - - curl -fsSL https://get.docker.com | sh - - echo '{"experimental":"enabled"}' | sudo tee /etc/docker/daemon.json - - mkdir -p $HOME/.docker - - echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json - - sudo service docker start - - > - if [ ! -z "${DOCKERHUB_PULL_USERNAME:-}" ]; then - set +x - echo "${DOCKERHUB_PULL_PASSWORD}" | docker login --username "${DOCKERHUB_PULL_USERNAME}" --password-stdin - set -x - fi +- curl -fsSL https://get.docker.com | sh +- echo '{"experimental":"enabled"}' | sudo tee /etc/docker/daemon.json +- mkdir -p $HOME/.docker +- echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json +- sudo service docker start +- > + if [ ! -z "${DOCKERHUB_PULL_USERNAME:-}" ]; then + set +x + echo "${DOCKERHUB_PULL_PASSWORD}" | docker login --username "${DOCKERHUB_PULL_USERNAME}" --password-stdin + set -x + fi +- docker --version install: -- docker --version - docker-compose up -d - sleep 10 From 17c90846e10741d7901993bd34fb23f7213ae4f4 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Fri, 15 Jan 2021 07:30:49 +0200 Subject: [PATCH 14/14] Fixed syntax bug in functions service --- app/controllers/api/functions.php | 2 +- app/workers/functions.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 54df37ab21..0572b8137c 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -157,7 +157,7 @@ App::get('/v1/functions/:functionId/usage') throw new Exception('Function not found', 404); } - if($App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + if(App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { $period = [ '24h' => [ 'start' => DateTime::createFromFormat('U', \strtotime('-24 hours')), diff --git a/app/workers/functions.php b/app/workers/functions.php index bb74bb0e60..577e847337 100644 --- a/app/workers/functions.php +++ b/app/workers/functions.php @@ -471,7 +471,7 @@ class FunctionsV1 ->setParam('networkResponseSize', 0) ; - if($App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + if(App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { $usage->trigger(); }