mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 00:49:02 +00:00
Merge pull request #9650 from appwrite/feat-exp-scheme
feat: exp scheme
This commit is contained in:
commit
dbadfa7bf8
15 changed files with 348 additions and 224 deletions
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
|
@ -283,8 +283,6 @@ jobs:
|
|||
name: E2E Service Test (Dev Keys)
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Network\Platform;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\System\System;
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ $console = [
|
|||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Localhost',
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'hostname' => 'localhost',
|
||||
], // Current host is added on app init
|
||||
],
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use Appwrite\Event\StatsUsage;
|
|||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Hooks\Hooks;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\Redirect;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
|
|
@ -60,7 +61,6 @@ use Utopia\System\System;
|
|||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Host;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
|
@ -1182,8 +1182,8 @@ App::get('/v1/account/sessions/oauth2/:provider')
|
|||
->label('abuse-limit', 50)
|
||||
->label('abuse-key', 'ip:{ip}')
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn ($node) => (!$node['mock'])))) . '.')
|
||||
->param('success', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients', 'devKey'])
|
||||
->param('failure', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients', 'devKey'])
|
||||
->param('success', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['platforms', 'devKey'])
|
||||
->param('failure', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['platforms', 'devKey'])
|
||||
->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
|
|
@ -1282,7 +1282,6 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) {
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
|
|
@ -1779,8 +1778,8 @@ App::get('/v1/account/tokens/oauth2/:provider')
|
|||
->label('abuse-limit', 50)
|
||||
->label('abuse-key', 'ip:{ip}')
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn ($node) => (!$node['mock'])))) . '.')
|
||||
->param('success', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients', 'devKey'])
|
||||
->param('failure', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients', 'devKey'])
|
||||
->param('success', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['platforms', 'devKey'])
|
||||
->param('failure', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['platforms', 'devKey'])
|
||||
->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
|
|
@ -1860,7 +1859,7 @@ App::post('/v1/account/tokens/magic-url')
|
|||
->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}'])
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients', 'devKey'])
|
||||
->param('url', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['platforms', 'devKey'])
|
||||
->param('phrase', false, new Boolean(), 'Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
|
|
@ -3146,7 +3145,7 @@ App::post('/v1/account/recovery')
|
|||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}'])
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients', 'devKey'])
|
||||
->param('url', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['platforms', 'devKey'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
|
|
@ -3413,7 +3412,7 @@ App::post('/v1/account/verification')
|
|||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},userId:{userId}')
|
||||
->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients', 'devKey']) // TODO add built-in confirm page
|
||||
->param('url', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['platforms', 'devKey']) // TODO add built-in confirm page
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ use Appwrite\Event\Mail;
|
|||
use Appwrite\Event\Validator\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Hooks\Hooks;
|
||||
use Appwrite\Network\Platform;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
|
|
@ -1790,7 +1790,7 @@ App::post('/v1/projects/:projectId/platforms')
|
|||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', null, new WhiteList([Origin::CLIENT_TYPE_WEB, Origin::CLIENT_TYPE_FLUTTER_WEB, Origin::CLIENT_TYPE_FLUTTER_IOS, Origin::CLIENT_TYPE_FLUTTER_ANDROID, Origin::CLIENT_TYPE_FLUTTER_LINUX, Origin::CLIENT_TYPE_FLUTTER_MACOS, Origin::CLIENT_TYPE_FLUTTER_WINDOWS, Origin::CLIENT_TYPE_APPLE_IOS, Origin::CLIENT_TYPE_APPLE_MACOS, Origin::CLIENT_TYPE_APPLE_WATCHOS, Origin::CLIENT_TYPE_APPLE_TVOS, Origin::CLIENT_TYPE_ANDROID, Origin::CLIENT_TYPE_UNITY, Origin::CLIENT_TYPE_REACT_NATIVE_IOS, Origin::CLIENT_TYPE_REACT_NATIVE_ANDROID], true), 'Platform type.')
|
||||
->param('type', null, new WhiteList([Platform::TYPE_WEB, Platform::TYPE_FLUTTER_WEB, Platform::TYPE_FLUTTER_IOS, Platform::TYPE_FLUTTER_ANDROID, Platform::TYPE_FLUTTER_LINUX, Platform::TYPE_FLUTTER_MACOS, Platform::TYPE_FLUTTER_WINDOWS, Platform::TYPE_APPLE_IOS, Platform::TYPE_APPLE_MACOS, Platform::TYPE_APPLE_WATCHOS, Platform::TYPE_APPLE_TVOS, Platform::TYPE_ANDROID, Platform::TYPE_UNITY, Platform::TYPE_REACT_NATIVE_IOS, Platform::TYPE_REACT_NATIVE_ANDROID], true), 'Platform type.')
|
||||
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
|
||||
->param('key', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.', true)
|
||||
->param('store', '', new Text(256), 'App store or Google Play store ID. Max length: 256 chars.', true)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use Appwrite\Event\Messaging;
|
|||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\Redirect;
|
||||
use Appwrite\Platform\Workers\Deletes;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
|
|
@ -50,7 +51,6 @@ use Utopia\Locale\Locale;
|
|||
use Utopia\System\System;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\Host;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
|
@ -466,7 +466,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
}
|
||||
return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE);
|
||||
}, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project'])
|
||||
->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients', 'devKey']) // TODO add our own built-in confirm page
|
||||
->param('url', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['platforms', 'devKey']) // TODO add our own built-in confirm page
|
||||
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use Appwrite\Auth\OAuth2\Github as OAuth2Github;
|
|||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Redirect;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
|
|
@ -53,7 +54,6 @@ use Utopia\Detector\Detector\Runtime;
|
|||
use Utopia\Detector\Detector\Strategy;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Host;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\VCS\Adapter\Git\GitHub;
|
||||
|
|
@ -426,8 +426,8 @@ App::get('/v1/vcs/github/authorize')
|
|||
type: MethodType::WEBAUTH,
|
||||
hide: true,
|
||||
))
|
||||
->param('success', '', fn ($clients) => new Host($clients), 'URL to redirect back to console after a successful installation attempt.', true, ['clients'])
|
||||
->param('failure', '', fn ($clients) => new Host($clients), 'URL to redirect back to console after a failed installation attempt.', true, ['clients'])
|
||||
->param('success', '', fn ($platforms) => new Redirect($platforms), 'URL to redirect back to console after a successful installation attempt.', true, ['platforms'])
|
||||
->param('failure', '', fn ($platforms) => new Redirect($platforms), 'URL to redirect back to console after a failed installation attempt.', true, ['platforms'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ use Utopia\Logger\Log\User;
|
|||
use Utopia\Logger\Logger;
|
||||
use Utopia\Platform\Service;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
Config::setParam('domainVerification', false);
|
||||
|
|
@ -799,6 +798,7 @@ App::init()
|
|||
->inject('getProjectDB')
|
||||
->inject('locale')
|
||||
->inject('localeCodes')
|
||||
->inject('platforms')
|
||||
->inject('geodb')
|
||||
->inject('queueForStatsUsage')
|
||||
->inject('queueForEvents')
|
||||
|
|
@ -811,7 +811,7 @@ App::init()
|
|||
->inject('apiKey')
|
||||
->inject('httpReferrer')
|
||||
->inject('httpReferrerSafe')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, string $httpReferrer, string $httpReferrerSafe) {
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $platforms, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, string $httpReferrer, string $httpReferrerSafe) {
|
||||
/*
|
||||
* Appwrite Router
|
||||
*/
|
||||
|
|
@ -1030,11 +1030,12 @@ App::init()
|
|||
* Skip this check for non-web platforms which are not required to send an origin header
|
||||
*/
|
||||
$origin = $request->getOrigin($request->getReferer(''));
|
||||
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
||||
$originValidator = new Origin($platforms);
|
||||
|
||||
if (
|
||||
!$originValidator->isValid($origin)
|
||||
&& $devKey->isEmpty()
|
||||
$devKey->isEmpty()
|
||||
&& !empty($origin)
|
||||
&& !$originValidator->isValid($origin)
|
||||
&& \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE])
|
||||
&& $route->getLabel('origin', false) !== '*'
|
||||
&& empty($request->getHeader('x-appwrite-key', ''))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use Appwrite\Event\StatsUsage;
|
|||
use Appwrite\Event\Webhook;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\GraphQL\Schema;
|
||||
use Appwrite\Network\Platform;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Executor\Executor;
|
||||
|
|
@ -127,11 +128,11 @@ App::setResource('queueForCertificates', function (Publisher $publisher) {
|
|||
App::setResource('queueForMigrations', function (Publisher $publisher) {
|
||||
return new Migration($publisher);
|
||||
}, ['publisher']);
|
||||
App::setResource('clients', function ($request, $console, $project) {
|
||||
App::setResource('platforms', function (Request $request, Document $console, Document $project) {
|
||||
$console->setAttribute('platforms', [ // Always allow current host
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Current Host',
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'hostname' => $request->getHostname(),
|
||||
], Document::SET_TYPE_APPEND);
|
||||
|
||||
|
|
@ -144,39 +145,32 @@ App::setResource('clients', function ($request, $console, $project) {
|
|||
}
|
||||
$console->setAttribute('platforms', [
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'name' => $hostname,
|
||||
'hostname' => $hostname,
|
||||
], Document::SET_TYPE_APPEND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get All verified client URLs for both console and current projects
|
||||
* + Filter for duplicated entries
|
||||
*/
|
||||
$clientsConsole = \array_map(
|
||||
fn ($node) => $node['hostname'],
|
||||
\array_filter(
|
||||
$console->getAttribute('platforms', []),
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && !empty($node['hostname']))
|
||||
)
|
||||
);
|
||||
|
||||
$clients = $clientsConsole;
|
||||
$platforms = $project->getAttribute('platforms', []);
|
||||
|
||||
foreach ($platforms as $node) {
|
||||
if (
|
||||
isset($node['type']) &&
|
||||
($node['type'] === Origin::CLIENT_TYPE_WEB ||
|
||||
$node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) &&
|
||||
!empty($node['hostname'])
|
||||
) {
|
||||
$clients[] = $node['hostname'];
|
||||
}
|
||||
// Add `exp` and `appwrite-callback-{projectId}` schemes
|
||||
if (!$project->isEmpty() && $project->getId() !== 'console') {
|
||||
$project->setAttribute('platforms', [
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'type' => Platform::TYPE_SCHEME,
|
||||
'name' => 'Expo',
|
||||
'key' => 'exp',
|
||||
], Document::SET_TYPE_APPEND);
|
||||
$project->setAttribute('platforms', [
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'type' => Platform::TYPE_SCHEME,
|
||||
'name' => 'Appwrite Callback',
|
||||
'key' => 'appwrite-callback-' . $project->getId(),
|
||||
], Document::SET_TYPE_APPEND);
|
||||
}
|
||||
|
||||
return \array_unique($clients);
|
||||
return [
|
||||
...$console->getAttribute('platforms', []),
|
||||
...$project->getAttribute('platforms', []),
|
||||
];
|
||||
}, ['request', 'console', 'project']);
|
||||
|
||||
App::setResource('user', function ($mode, $project, $console, $request, $response, $dbForProject, $dbForPlatform) {
|
||||
|
|
@ -960,7 +954,7 @@ App::setResource('httpReferrer', function (Request $request): string {
|
|||
return $referrer;
|
||||
}, ['request']);
|
||||
|
||||
App::setResource('httpReferrerSafe', function (Request $request, string $httpReferrer, array $clients, Database $dbForPlatform, Document $project, App $utopia): string {
|
||||
App::setResource('httpReferrerSafe', function (Request $request, string $httpReferrer, array $platforms, Database $dbForPlatform, Document $project, App $utopia): string {
|
||||
$origin = \parse_url($request->getOrigin($httpReferrer), PHP_URL_HOST);
|
||||
$protocol = \parse_url($request->getOrigin($httpReferrer), PHP_URL_SCHEME);
|
||||
$port = \parse_url($request->getOrigin($httpReferrer), PHP_URL_PORT);
|
||||
|
|
@ -973,8 +967,8 @@ App::setResource('httpReferrerSafe', function (Request $request, string $httpRef
|
|||
}
|
||||
|
||||
// Safe if added as web platform
|
||||
$validator = new Hostname($clients);
|
||||
if ($validator->isValid($origin)) {
|
||||
$originValidator = new Origin($platforms);
|
||||
if ($originValidator->isValid($request->getOrigin($httpReferrer))) {
|
||||
return $referrer;
|
||||
}
|
||||
|
||||
|
|
@ -1002,4 +996,4 @@ App::setResource('httpReferrerSafe', function (Request $request, string $httpRef
|
|||
$port = \parse_url($request->getOrigin($httpReferrer), PHP_URL_PORT);
|
||||
$referrer = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
|
||||
return $referrer;
|
||||
}, ['request', 'httpReferrer', 'clients', 'dbForPlatform', 'project', 'utopia']);
|
||||
}, ['request', 'httpReferrer', 'platforms', 'dbForPlatform', 'project', 'utopia']);
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
|||
}
|
||||
|
||||
$timelimit = $app->getResource('timelimit');
|
||||
$console = $app->getResource('console'); /** @var Document $console */
|
||||
$platforms = $app->getResource('platforms');
|
||||
$user = $app->getResource('user'); /** @var Document $user */
|
||||
|
||||
/*
|
||||
|
|
@ -557,9 +557,9 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
|||
* Skip this check for non-web platforms which are not required to send an origin header.
|
||||
*/
|
||||
$origin = $request->getOrigin();
|
||||
$originValidator = new Origin(array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
||||
$originValidator = new Origin($platforms);
|
||||
|
||||
if (!$originValidator->isValid($origin) && $project->getId() !== 'console') {
|
||||
if (!empty($origin) && !$originValidator->isValid($origin) && $project->getId() !== 'console') {
|
||||
throw new Exception(Exception::REALTIME_POLICY_VIOLATION, $originValidator->getDescription());
|
||||
}
|
||||
|
||||
|
|
|
|||
151
src/Appwrite/Network/Platform.php
Normal file
151
src/Appwrite/Network/Platform.php
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Network;
|
||||
|
||||
class Platform
|
||||
{
|
||||
public const TYPE_UNKNOWN = 'unknown';
|
||||
public const TYPE_WEB = 'web';
|
||||
public const TYPE_FLUTTER_IOS = 'flutter-ios';
|
||||
public const TYPE_FLUTTER_ANDROID = 'flutter-android';
|
||||
public const TYPE_FLUTTER_MACOS = 'flutter-macos';
|
||||
public const TYPE_FLUTTER_WINDOWS = 'flutter-windows';
|
||||
public const TYPE_FLUTTER_LINUX = 'flutter-linux';
|
||||
public const TYPE_FLUTTER_WEB = 'flutter-web';
|
||||
public const TYPE_APPLE_IOS = 'apple-ios';
|
||||
public const TYPE_APPLE_MACOS = 'apple-macos';
|
||||
public const TYPE_APPLE_WATCHOS = 'apple-watchos';
|
||||
public const TYPE_APPLE_TVOS = 'apple-tvos';
|
||||
public const TYPE_ANDROID = 'android';
|
||||
public const TYPE_UNITY = 'unity';
|
||||
public const TYPE_REACT_NATIVE_IOS = 'react-native-ios';
|
||||
public const TYPE_REACT_NATIVE_ANDROID = 'react-native-android';
|
||||
public const TYPE_SCHEME = 'scheme';
|
||||
|
||||
public const SCHEME_HTTP = 'http';
|
||||
public const SCHEME_HTTPS = 'https';
|
||||
public const SCHEME_IOS = 'appwrite-ios';
|
||||
public const SCHEME_MACOS = 'appwrite-macos';
|
||||
public const SCHEME_WATCHOS = 'appwrite-watchos';
|
||||
public const SCHEME_TVOS = 'appwrite-tvos';
|
||||
public const SCHEME_ANDROID = 'appwrite-android';
|
||||
public const SCHEME_WINDOWS = 'appwrite-windows';
|
||||
public const SCHEME_LINUX = 'appwrite-linux';
|
||||
|
||||
/**
|
||||
* @var array<string, string> Map scheme types to user-friendly platform names.
|
||||
*/
|
||||
private static array $names = [
|
||||
self::SCHEME_HTTP => 'Web',
|
||||
self::SCHEME_HTTPS => 'Web',
|
||||
self::SCHEME_IOS => 'iOS',
|
||||
self::SCHEME_MACOS => 'macOS',
|
||||
self::SCHEME_WATCHOS => 'watchOS',
|
||||
self::SCHEME_TVOS => 'tvOS',
|
||||
self::SCHEME_ANDROID => 'Android',
|
||||
self::SCHEME_WINDOWS => 'Windows',
|
||||
self::SCHEME_LINUX => 'Linux',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get user-friendly platform name from a scheme.
|
||||
*
|
||||
* @param string|null $scheme
|
||||
* @return string Empty string if scheme is not found.
|
||||
*/
|
||||
public static function getNameByScheme(?string $scheme): string
|
||||
{
|
||||
return self::$names[$scheme] ?? '';
|
||||
}
|
||||
|
||||
public static function getHostnames(array $platforms): array
|
||||
{
|
||||
$hostnames = [];
|
||||
foreach ($platforms as $platform) {
|
||||
$type = strtolower($platform['type'] ?? self::TYPE_UNKNOWN);
|
||||
$hostname = strtolower($platform['hostname'] ?? '');
|
||||
$key = strtolower($platform['key'] ?? '');
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_WEB:
|
||||
case self::TYPE_FLUTTER_WEB:
|
||||
if (!empty($hostname)) {
|
||||
$hostnames[] = $hostname;
|
||||
}
|
||||
break;
|
||||
case self::TYPE_FLUTTER_IOS:
|
||||
case self::TYPE_FLUTTER_ANDROID:
|
||||
case self::TYPE_FLUTTER_MACOS:
|
||||
case self::TYPE_FLUTTER_WINDOWS:
|
||||
case self::TYPE_FLUTTER_LINUX:
|
||||
case self::TYPE_ANDROID:
|
||||
case self::TYPE_APPLE_IOS:
|
||||
case self::TYPE_APPLE_MACOS:
|
||||
case self::TYPE_APPLE_WATCHOS:
|
||||
case self::TYPE_APPLE_TVOS:
|
||||
case self::TYPE_REACT_NATIVE_IOS:
|
||||
case self::TYPE_REACT_NATIVE_ANDROID:
|
||||
case self::TYPE_UNITY:
|
||||
if (!empty($key)) {
|
||||
$hostnames[] = $key;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array_unique($hostnames);
|
||||
}
|
||||
|
||||
public static function getSchemes(array $platforms): array
|
||||
{
|
||||
$schemes = [];
|
||||
foreach ($platforms as $platform) {
|
||||
$type = strtolower($platform['type'] ?? self::TYPE_UNKNOWN);
|
||||
$scheme = strtolower($platform['key'] ?? '');
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_SCHEME:
|
||||
if (!empty($scheme) && preg_match('/^[a-z][a-z0-9+.-]*$/', $scheme)) {
|
||||
$schemes[] = $scheme;
|
||||
}
|
||||
break;
|
||||
case self::TYPE_WEB:
|
||||
case self::TYPE_FLUTTER_WEB:
|
||||
$schemes[] = self::SCHEME_HTTP;
|
||||
$schemes[] = self::SCHEME_HTTPS;
|
||||
break;
|
||||
case self::TYPE_FLUTTER_IOS:
|
||||
case self::TYPE_APPLE_IOS:
|
||||
case self::TYPE_REACT_NATIVE_IOS:
|
||||
$schemes[] = self::SCHEME_IOS;
|
||||
break;
|
||||
case self::TYPE_FLUTTER_ANDROID:
|
||||
case self::TYPE_ANDROID:
|
||||
case self::TYPE_REACT_NATIVE_ANDROID:
|
||||
$schemes[] = self::SCHEME_ANDROID;
|
||||
break;
|
||||
case self::TYPE_FLUTTER_MACOS:
|
||||
case self::TYPE_APPLE_MACOS:
|
||||
$schemes[] = self::SCHEME_MACOS;
|
||||
break;
|
||||
case self::TYPE_FLUTTER_WINDOWS:
|
||||
case self::TYPE_UNITY:
|
||||
$schemes[] = self::SCHEME_WINDOWS;
|
||||
break;
|
||||
case self::TYPE_FLUTTER_LINUX:
|
||||
$schemes[] = self::SCHEME_LINUX;
|
||||
break;
|
||||
case self::TYPE_APPLE_WATCHOS:
|
||||
$schemes[] = self::SCHEME_WATCHOS;
|
||||
break;
|
||||
case self::TYPE_APPLE_TVOS:
|
||||
$schemes[] = self::SCHEME_TVOS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array_unique($schemes);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,150 +2,77 @@
|
|||
|
||||
namespace Appwrite\Network\Validator;
|
||||
|
||||
use Appwrite\Network\Platform;
|
||||
use Utopia\Validator;
|
||||
use Utopia\Validator\Hostname;
|
||||
|
||||
class Origin extends Validator
|
||||
{
|
||||
public const CLIENT_TYPE_UNKNOWN = 'unknown';
|
||||
public const CLIENT_TYPE_WEB = 'web';
|
||||
public const CLIENT_TYPE_FLUTTER_IOS = 'flutter-ios';
|
||||
public const CLIENT_TYPE_FLUTTER_ANDROID = 'flutter-android';
|
||||
public const CLIENT_TYPE_FLUTTER_MACOS = 'flutter-macos';
|
||||
public const CLIENT_TYPE_FLUTTER_WINDOWS = 'flutter-windows';
|
||||
public const CLIENT_TYPE_FLUTTER_LINUX = 'flutter-linux';
|
||||
public const CLIENT_TYPE_FLUTTER_WEB = 'flutter-web';
|
||||
public const CLIENT_TYPE_APPLE_IOS = 'apple-ios';
|
||||
public const CLIENT_TYPE_APPLE_MACOS = 'apple-macos';
|
||||
public const CLIENT_TYPE_APPLE_WATCHOS = 'apple-watchos';
|
||||
public const CLIENT_TYPE_APPLE_TVOS = 'apple-tvos';
|
||||
public const CLIENT_TYPE_ANDROID = 'android';
|
||||
public const CLIENT_TYPE_UNITY = 'unity';
|
||||
public const CLIENT_TYPE_REACT_NATIVE_IOS = 'react-native-ios';
|
||||
public const CLIENT_TYPE_REACT_NATIVE_ANDROID = 'react-native-android';
|
||||
|
||||
|
||||
public const SCHEME_TYPE_HTTP = 'http';
|
||||
public const SCHEME_TYPE_HTTPS = 'https';
|
||||
public const SCHEME_TYPE_IOS = 'appwrite-ios';
|
||||
public const SCHEME_TYPE_MACOS = 'appwrite-macos';
|
||||
public const SCHEME_TYPE_WATCHOS = 'appwrite-watchos';
|
||||
public const SCHEME_TYPE_TVOS = 'appwrite-tvos';
|
||||
public const SCHEME_TYPE_ANDROID = 'appwrite-android';
|
||||
public const SCHEME_TYPE_WINDOWS = 'appwrite-windows';
|
||||
public const SCHEME_TYPE_LINUX = 'appwrite-linux';
|
||||
protected array $hostnames = [];
|
||||
protected array $schemes = [];
|
||||
protected ?string $scheme = null;
|
||||
protected ?string $host = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* Constructor
|
||||
*
|
||||
* @param array<\Utopia\Database\Document> $platforms
|
||||
*/
|
||||
protected $platforms = [
|
||||
self::SCHEME_TYPE_HTTP => 'Web',
|
||||
self::SCHEME_TYPE_HTTPS => 'Web',
|
||||
self::SCHEME_TYPE_IOS => 'iOS',
|
||||
self::SCHEME_TYPE_MACOS => 'macOS',
|
||||
self::SCHEME_TYPE_WATCHOS => 'watchOS',
|
||||
self::SCHEME_TYPE_TVOS => 'tvOS',
|
||||
self::SCHEME_TYPE_ANDROID => 'Android',
|
||||
self::SCHEME_TYPE_WINDOWS => 'Windows',
|
||||
self::SCHEME_TYPE_LINUX => 'Linux',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $clients = [
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $client = self::CLIENT_TYPE_UNKNOWN;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $host = '';
|
||||
|
||||
/**
|
||||
* @param string $target
|
||||
*/
|
||||
public function __construct($platforms)
|
||||
public function __construct(array $platforms)
|
||||
{
|
||||
foreach ($platforms as $platform) {
|
||||
$type = (isset($platform['type'])) ? $platform['type'] : '';
|
||||
|
||||
switch ($type) {
|
||||
case self::CLIENT_TYPE_WEB:
|
||||
case self::CLIENT_TYPE_FLUTTER_WEB:
|
||||
$this->clients[] = (isset($platform['hostname'])) ? $platform['hostname'] : '';
|
||||
break;
|
||||
|
||||
case self::CLIENT_TYPE_FLUTTER_IOS:
|
||||
case self::CLIENT_TYPE_FLUTTER_ANDROID:
|
||||
case self::CLIENT_TYPE_FLUTTER_MACOS:
|
||||
case self::CLIENT_TYPE_FLUTTER_WINDOWS:
|
||||
case self::CLIENT_TYPE_FLUTTER_LINUX:
|
||||
case self::CLIENT_TYPE_ANDROID:
|
||||
case self::CLIENT_TYPE_APPLE_IOS:
|
||||
case self::CLIENT_TYPE_APPLE_MACOS:
|
||||
case self::CLIENT_TYPE_APPLE_WATCHOS:
|
||||
case self::CLIENT_TYPE_APPLE_TVOS:
|
||||
case self::CLIENT_TYPE_REACT_NATIVE_IOS:
|
||||
case self::CLIENT_TYPE_REACT_NATIVE_ANDROID:
|
||||
$this->clients[] = (isset($platform['key'])) ? $platform['key'] : '';
|
||||
break;
|
||||
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->hostnames = Platform::getHostnames($platforms);
|
||||
$this->schemes = Platform::getSchemes($platforms);
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
if (!\array_key_exists($this->client, $this->platforms)) {
|
||||
return 'Unsupported platform';
|
||||
}
|
||||
|
||||
return 'Invalid Origin. Register your new client (' . $this->host . ') as a new '
|
||||
. $this->platforms[$this->client] . ' platform on your project console dashboard';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Origin has been allowed
|
||||
* for access to the API
|
||||
*
|
||||
* @param mixed $origin
|
||||
*
|
||||
* Check if Origin is valid.
|
||||
* @param mixed $origin The Origin URI.
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($origin): bool
|
||||
{
|
||||
if (!is_string($origin)) {
|
||||
$this->scheme = null;
|
||||
$this->host = null;
|
||||
|
||||
if (!is_string($origin) || empty($origin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$scheme = \parse_url($origin, PHP_URL_SCHEME);
|
||||
$host = \parse_url($origin, PHP_URL_HOST);
|
||||
$this->scheme = $this->parseScheme($origin);
|
||||
$this->host = strtolower(parse_url($origin, PHP_URL_HOST) ?? '');
|
||||
|
||||
$this->host = $host;
|
||||
$this->client = $scheme;
|
||||
if (in_array($this->scheme, [Platform::SCHEME_HTTP, Platform::SCHEME_HTTPS], true)) {
|
||||
$validator = new Hostname($this->hostnames);
|
||||
return $validator->isValid($this->host);
|
||||
}
|
||||
|
||||
if (empty($host)) {
|
||||
if (!empty($this->scheme) && in_array($this->scheme, $this->schemes, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$validator = new Hostname($this->clients);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $validator->isValid($host);
|
||||
/**
|
||||
* Get Description
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
$platform = $this->scheme ? Platform::getNameByScheme($this->scheme) : null;
|
||||
$host = $this->host ? '(' . $this->host . ')' : '';
|
||||
|
||||
if (empty($this->host) && empty($this->scheme)) {
|
||||
return 'Invalid Origin.';
|
||||
}
|
||||
|
||||
return 'Invalid Origin. Register your new client ' . $host . ' as a new '
|
||||
. $platform . ' platform on your project console dashboard';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is array
|
||||
*
|
||||
* Function will return true if object is array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isArray(): bool
|
||||
|
|
@ -155,13 +82,35 @@ class Origin extends Validator
|
|||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* Returns validator type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return self::TYPE_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the scheme from a URI string.
|
||||
*
|
||||
* @param string $uri The URI string to parse.
|
||||
* @return string|null The extracted scheme string (e.g., "http", "exp", "mailto")
|
||||
*/
|
||||
public function parseScheme(string $uri): ?string
|
||||
{
|
||||
$uri = trim($uri);
|
||||
if ($uri === '') {
|
||||
return null; // No scheme in empty string
|
||||
}
|
||||
|
||||
$scheme = parse_url($uri, PHP_URL_SCHEME);
|
||||
if ($scheme === false) {
|
||||
if (preg_match('/^([a-z][a-z0-9+.-]*):/i', $uri, $matches)) {
|
||||
return $matches[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return $scheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
src/Appwrite/Network/Validator/Redirect.php
Normal file
25
src/Appwrite/Network/Validator/Redirect.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Network\Validator;
|
||||
|
||||
use Appwrite\Network\Platform;
|
||||
|
||||
class Redirect extends Origin
|
||||
{
|
||||
/**
|
||||
* Get Description
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
$platform = Platform::getNameByScheme($this->scheme);
|
||||
$host = $this->host ? '(' . $this->host . ')' : '';
|
||||
|
||||
if (empty($this->host) && empty($this->scheme)) {
|
||||
return 'Invalid URI.';
|
||||
}
|
||||
|
||||
return 'Invalid URI. Register your new client ' . $host . ' as a new '
|
||||
. $platform . ' platform on your project console dashboard';
|
||||
}
|
||||
}
|
||||
|
|
@ -4637,7 +4637,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'failure' => 'https://example.com'
|
||||
]);
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('Invalid `success` param: URL host must be one of: localhost, appwrite.io, *.appwrite.io', $response['body']);
|
||||
|
||||
/** Test oauth2 with devKey and now get oauth2 is disabled */
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, [
|
||||
|
|
@ -4660,7 +4659,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'url' => 'https://example.com',
|
||||
]);
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertEquals('Invalid `url` param: URL host must be one of: localhost, appwrite.io, *.appwrite.io', $response['body']['message']);
|
||||
|
||||
/** Test hostname in Magic URL with devKey */
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/magic-url', [
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ trait RealtimeBase
|
|||
$projectId = $this->getProject()['$id'];
|
||||
}
|
||||
|
||||
$headers = array_merge(
|
||||
[
|
||||
"Origin" => "appwrite.test",
|
||||
],
|
||||
$headers
|
||||
);
|
||||
|
||||
$query = [
|
||||
"project" => $projectId,
|
||||
"channels" => $channels,
|
||||
|
|
@ -49,7 +42,7 @@ trait RealtimeBase
|
|||
|
||||
public function testConnectionFailureMissingChannels(): void
|
||||
{
|
||||
$client = $this->getWebsocket();
|
||||
$client = $this->getWebsocket([]);
|
||||
$payload = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey("type", $payload);
|
||||
|
|
@ -64,14 +57,7 @@ trait RealtimeBase
|
|||
|
||||
public function testConnectionFailureUnknownProject(): void
|
||||
{
|
||||
$client = new WebSocketClient(
|
||||
"ws://appwrite-traefik/v1/realtime?project=123",
|
||||
[
|
||||
"headers" => [
|
||||
"Origin" => "appwrite.test",
|
||||
],
|
||||
]
|
||||
);
|
||||
$client = $this->getWebsocket(projectId: '123');
|
||||
$payload = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey("type", $payload);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Tests\Unit\Network\Validators;
|
||||
|
||||
use Appwrite\Network\Platform;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
|
|
@ -14,62 +15,84 @@ class OriginTest extends TestCase
|
|||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Production',
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'hostname' => 'appwrite.io',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Development',
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'hostname' => 'appwrite.test',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Localhost',
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'hostname' => 'localhost',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Flutter',
|
||||
'type' => Origin::CLIENT_TYPE_FLUTTER_WEB,
|
||||
'type' => Platform::TYPE_FLUTTER_WEB,
|
||||
'hostname' => 'appwrite.flutter',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Expo',
|
||||
'type' => Platform::TYPE_SCHEME,
|
||||
'key' => 'exp',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Appwrite Callback',
|
||||
'type' => Platform::TYPE_SCHEME,
|
||||
'key' => 'appwrite-callback-123',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals($validator->isValid('https://localhost'), true);
|
||||
$this->assertEquals($validator->isValid('http://localhost'), true);
|
||||
$this->assertEquals($validator->isValid('http://localhost:80'), true);
|
||||
$this->assertEquals(false, $validator->isValid(''));
|
||||
$this->assertEquals(false, $validator->isValid('/'));
|
||||
|
||||
$this->assertEquals($validator->isValid('https://appwrite.io'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.io'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.io:80'), true);
|
||||
$this->assertEquals(true, $validator->isValid('https://localhost'));
|
||||
$this->assertEquals(true, $validator->isValid('http://localhost'));
|
||||
$this->assertEquals(true, $validator->isValid('http://localhost:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('https://appwrite.test'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.test'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.test:80'), true);
|
||||
$this->assertEquals(true, $validator->isValid('https://appwrite.io'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.io'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.io:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('https://appwrite.flutter'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.flutter'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.flutter:80'), true);
|
||||
$this->assertEquals(true, $validator->isValid('https://appwrite.test'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.test'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.test:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('https://example.com'), false);
|
||||
$this->assertEquals($validator->isValid('http://example.com'), false);
|
||||
$this->assertEquals($validator->isValid('http://example.com:80'), false);
|
||||
$this->assertEquals(true, $validator->isValid('https://appwrite.flutter'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.flutter'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.flutter:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-ios://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new iOS platform on your project console dashboard');
|
||||
$this->assertEquals(false, $validator->isValid('https://example.com'));
|
||||
$this->assertEquals(false, $validator->isValid('http://example.com'));
|
||||
$this->assertEquals(false, $validator->isValid('http://example.com:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-android://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new Android platform on your project console dashboard');
|
||||
$this->assertEquals(true, $validator->isValid('exp://'));
|
||||
$this->assertEquals(true, $validator->isValid('exp:///'));
|
||||
$this->assertEquals(true, $validator->isValid('exp://index'));
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-macos://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new macOS platform on your project console dashboard');
|
||||
$this->assertEquals(true, $validator->isValid('appwrite-callback-123://'));
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-callback-456://'));
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-linux://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new Linux platform on your project console dashboard');
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-ios://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new iOS platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-windows://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new Windows platform on your project console dashboard');
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-android://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Android platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-macos://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new macOS platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-linux://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Linux platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-windows://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Windows platform on your project console dashboard', $validator->getDescription());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue