mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge remote-tracking branch 'origin/1.8.x' into documents-db-api
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Filter;
|
||||
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class BranchDomain implements Filter
|
||||
{
|
||||
/**
|
||||
* Maximum length for branch prefix in domain name
|
||||
*/
|
||||
public const BRANCH_PREFIX_MAX_LENGTH = 16;
|
||||
|
||||
/**
|
||||
* Length of hash suffix when branch name exceeds max length
|
||||
*/
|
||||
public const HASH_SUFFIX_LENGTH = 7;
|
||||
|
||||
/**
|
||||
* Pre-process branch name to a valid domain name.
|
||||
*
|
||||
* Input should be an array with:
|
||||
* - 'branch' (string): The branch name
|
||||
* - 'resourceId' (string): The resource ID (site or function)
|
||||
* - 'projectId' (string): The project ID
|
||||
* - 'sitesDomain' (string): The base sites domain
|
||||
*/
|
||||
public function apply(mixed $input): mixed
|
||||
{
|
||||
$branch = $input['branch'] ?? '';
|
||||
$resourceId = $input['resourceId'] ?? '';
|
||||
$projectId = $input['projectId'] ?? '';
|
||||
$sitesDomain = $input['sitesDomain'] ?? '';
|
||||
|
||||
$branchPrefix = $this->generateBranchPrefix($branch);
|
||||
$resourceProjectHash = substr(hash('sha256', $resourceId . $projectId), 0, self::HASH_SUFFIX_LENGTH);
|
||||
$domain = \strtolower("branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}");
|
||||
return $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a branch prefix for domain name from a branch name.
|
||||
* Takes up to 16 characters, sanitizes them for domain use,
|
||||
* and appends a hash suffix if the branch name is longer than 16 characters.
|
||||
*
|
||||
* @param string $branch The branch name
|
||||
* @return string The branch prefix for domain name
|
||||
*/
|
||||
private function generateBranchPrefix(string $branch): string
|
||||
{
|
||||
$branchPrefix = substr($branch, 0, self::BRANCH_PREFIX_MAX_LENGTH);
|
||||
$branchPrefix = $this->sanitizeBranchName($branchPrefix);
|
||||
|
||||
if (strlen($branch) > self::BRANCH_PREFIX_MAX_LENGTH) {
|
||||
$remainingChars = substr($branch, self::BRANCH_PREFIX_MAX_LENGTH);
|
||||
$branchPrefix .= '-' . substr(hash('sha256', $remainingChars), 0, self::HASH_SUFFIX_LENGTH);
|
||||
}
|
||||
|
||||
return $branchPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a branch name for use in a domain name.
|
||||
* Replaces any characters that are not alphanumeric or hyphens with hyphens,
|
||||
* and removes leading/trailing hyphens.
|
||||
*
|
||||
* @param string $branch The branch name to sanitize
|
||||
* @return string The sanitized branch name
|
||||
*/
|
||||
private function sanitizeBranchName(string $branch): string
|
||||
{
|
||||
$allowedChars = array_merge(
|
||||
Text::NUMBERS,
|
||||
Text::ALPHABET_UPPER,
|
||||
Text::ALPHABET_LOWER,
|
||||
['-']
|
||||
);
|
||||
$allowedCharsFlip = array_flip($allowedChars);
|
||||
|
||||
$sanitized = '';
|
||||
for ($i = 0; $i < \strlen($branch); $i++) {
|
||||
$char = $branch[$i];
|
||||
|
||||
if (isset($allowedCharsFlip[$char])) {
|
||||
$sanitized .= $char;
|
||||
} else {
|
||||
// Prevents two -- or more in a row
|
||||
if (strlen($sanitized) > 0 && $sanitized[strlen($sanitized) - 1] !== '-') {
|
||||
$sanitized .= '-';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trim($sanitized, '-');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Filter;
|
||||
|
||||
interface Filter
|
||||
{
|
||||
public function apply(mixed $input): mixed;
|
||||
}
|
||||
@@ -4,8 +4,10 @@ namespace Appwrite\Platform\Modules\Compute;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Filter\BranchDomain as BranchDomainFilter;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Compute\Validator\Specification as SpecificationValidator;
|
||||
use Appwrite\Platform\Permission as AppwritePermission;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
@@ -22,23 +24,7 @@ use Utopia\VCS\Exception\RepositoryNotFound;
|
||||
|
||||
class Base extends Action
|
||||
{
|
||||
/**
|
||||
* Permissions for resources in this project.
|
||||
*
|
||||
* @param string $teamId
|
||||
* @param string $projectId
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getPermissions(string $teamId, string $projectId): array
|
||||
{
|
||||
return [
|
||||
Permission::read(Role::team(ID::custom($teamId))),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'developer')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
|
||||
];
|
||||
}
|
||||
use AppwritePermission;
|
||||
|
||||
/**
|
||||
* Get default specification based on plan and available specifications.
|
||||
@@ -326,13 +312,12 @@ class Base extends Action
|
||||
|
||||
// VCS branch preview
|
||||
if (!empty($providerBranch)) {
|
||||
$branchPrefix = substr($providerBranch, 0, 16);
|
||||
if (strlen($providerBranch) > 16) {
|
||||
$remainingChars = substr($providerBranch, 16);
|
||||
$branchPrefix .= '-' . substr(hash('sha256', $remainingChars), 0, 7);
|
||||
}
|
||||
$resourceProjectHash = substr(hash('sha256', $site->getId() . $project->getId()), 0, 7);
|
||||
$domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}";
|
||||
$domain = (new BranchDomainFilter())->apply([
|
||||
'branch' => $providerBranch,
|
||||
'resourceId' => $site->getId(),
|
||||
'projectId' => $project->getId(),
|
||||
'sitesDomain' => $sitesDomain,
|
||||
]);
|
||||
$ruleId = md5($domain);
|
||||
try {
|
||||
$authorization->skip(
|
||||
|
||||
@@ -137,6 +137,7 @@ class Get extends Action
|
||||
}
|
||||
|
||||
$response->noContent();
|
||||
return;
|
||||
}
|
||||
|
||||
// Only occurs if type is added into whitelist, but not supported in action
|
||||
|
||||
@@ -9,6 +9,7 @@ use Appwrite\Event\Realtime;
|
||||
use Appwrite\Event\Screenshot;
|
||||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Event\Webhook;
|
||||
use Appwrite\Filter\BranchDomain as BranchDomainFilter;
|
||||
use Appwrite\Utopia\Response\Model\Deployment;
|
||||
use Appwrite\Vcs\Comment;
|
||||
use Exception;
|
||||
@@ -1013,16 +1014,6 @@ class Builds extends Action
|
||||
Console::log('Deployment activated');
|
||||
}
|
||||
|
||||
/** Screenshot site */
|
||||
if ($resource->getCollection() === 'sites') {
|
||||
$queueForScreenshots
|
||||
->setDeploymentId($deployment->getId())
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
|
||||
Console::log('Site screenshot queued');
|
||||
}
|
||||
|
||||
$this->afterDeploymentSuccess(
|
||||
$project,
|
||||
$deployment,
|
||||
@@ -1037,14 +1028,12 @@ class Builds extends Action
|
||||
// VCS branch
|
||||
$branchName = $deployment->getAttribute('providerBranch');
|
||||
if (!empty($branchName)) {
|
||||
$sitesDomain = $platform['sitesDomain'];
|
||||
$branchPrefix = substr($branchName, 0, 16);
|
||||
if (strlen($branchName) > 16) {
|
||||
$remainingChars = substr($branchName, 16);
|
||||
$branchPrefix .= '-' . substr(hash('sha256', $remainingChars), 0, 7);
|
||||
}
|
||||
$resourceProjectHash = substr(hash('sha256', $resource->getId() . $project->getId()), 0, 7);
|
||||
$domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}";
|
||||
$domain = (new BranchDomainFilter())->apply([
|
||||
'branch' => $branchName,
|
||||
'resourceId' => $resource->getId(),
|
||||
'projectId' => $project->getId(),
|
||||
'sitesDomain' => $platform['sitesDomain'],
|
||||
]);
|
||||
$ruleId = md5($domain);
|
||||
|
||||
try {
|
||||
@@ -1123,6 +1112,16 @@ class Builds extends Action
|
||||
$dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule);
|
||||
}
|
||||
|
||||
/** Screenshot site */
|
||||
if ($resource->getCollection() === 'sites') {
|
||||
$queueForScreenshots
|
||||
->setDeploymentId($deployment->getId())
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
|
||||
Console::log('Site screenshot queued');
|
||||
}
|
||||
|
||||
Console::info('Deployment action finished');
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning('Build failed:');
|
||||
|
||||
@@ -111,7 +111,12 @@ class Screenshots extends Action
|
||||
throw new \Exception('Bucket not found');
|
||||
}
|
||||
|
||||
$routerHost = System::getEnv('_APP_WORKER_SCREENSHOTS_ROUTER', 'http://appwrite');
|
||||
$routerHost = System::getEnv('_APP_WORKER_SCREENSHOTS_ROUTER', '');
|
||||
if (empty($routerHost)) {
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
|
||||
$routerHost = "$protocol://{$rule->getAttribute('domain')}";
|
||||
}
|
||||
|
||||
$configs = [
|
||||
'screenshotLight' => [
|
||||
'headers' => [ 'x-appwrite-hostname' => $rule->getAttribute('domain') ],
|
||||
|
||||
@@ -3,20 +3,9 @@
|
||||
namespace Appwrite\Platform\Modules\Projects\Http\Projects;
|
||||
|
||||
use Appwrite\Platform\Action as AppwriteAction;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Appwrite\Platform\Permission as AppwritePermission;
|
||||
|
||||
class Action extends AppwriteAction
|
||||
{
|
||||
protected function getPermissions(string $teamId, string $projectId): array
|
||||
{
|
||||
return [
|
||||
Permission::read(Role::team(ID::custom($teamId))),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'developer')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
|
||||
];
|
||||
}
|
||||
use AppwritePermission;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class Create extends Action
|
||||
$this->validateDomainRestrictions($domain, $platform);
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique();
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5(\strtolower($domain)) : ID::unique();
|
||||
$status = RULE_STATUS_CREATED;
|
||||
$owner = '';
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class Create extends Action
|
||||
$deployment = $dbForProject->getDocument('deployments', $function->getAttribute('deploymentId', ''));
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique();
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5(\strtolower($domain)) : ID::unique();
|
||||
$status = RULE_STATUS_CREATED;
|
||||
$owner = '';
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ class Create extends Action
|
||||
}
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique();
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5(\strtolower($domain)) : ID::unique();
|
||||
$status = RULE_STATUS_CREATED;
|
||||
$owner = '';
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class Create extends Action
|
||||
$deployment = $dbForProject->getDocument('deployments', $site->getAttribute('deploymentId', ''));
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique();
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5(\strtolower($domain)) : ID::unique();
|
||||
$status = RULE_STATUS_CREATED;
|
||||
$owner = '';
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform;
|
||||
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission as DbPermission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
trait Permission
|
||||
{
|
||||
/**
|
||||
* Permissions for projects & project resources.
|
||||
*
|
||||
* @param string $teamId
|
||||
* @param string $projectId
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissions(string $teamId, string $projectId): array
|
||||
{
|
||||
return [
|
||||
// Team-wide permissions
|
||||
DbPermission::read(Role::team(ID::custom($teamId), 'owner')),
|
||||
DbPermission::read(Role::team(ID::custom($teamId), 'developer')),
|
||||
DbPermission::update(Role::team(ID::custom($teamId), 'owner')),
|
||||
DbPermission::update(Role::team(ID::custom($teamId), 'developer')),
|
||||
DbPermission::delete(Role::team(ID::custom($teamId), 'owner')),
|
||||
DbPermission::delete(Role::team(ID::custom($teamId), 'developer')),
|
||||
// Project-wide permissions
|
||||
DbPermission::read(Role::team(ID::custom($teamId), "project-{$projectId}-owner")),
|
||||
DbPermission::read(Role::team(ID::custom($teamId), "project-{$projectId}-developer")),
|
||||
DbPermission::update(Role::team(ID::custom($teamId), "project-{$projectId}-owner")),
|
||||
DbPermission::update(Role::team(ID::custom($teamId), "project-{$projectId}-developer")),
|
||||
DbPermission::delete(Role::team(ID::custom($teamId), "project-{$projectId}-owner")),
|
||||
DbPermission::delete(Role::team(ID::custom($teamId), "project-{$projectId}-developer")),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ class User extends Document
|
||||
{
|
||||
$roles = [];
|
||||
|
||||
if (!$this->isPrivileged($authorization->getRoles()) && !$this->isApp($authorization->getRoles())) {
|
||||
if (!$this->isApp($authorization->getRoles())) {
|
||||
if ($this->getId()) {
|
||||
$roles[] = Role::user($this->getId())->toString();
|
||||
$roles[] = Role::users()->toString();
|
||||
|
||||
Reference in New Issue
Block a user