diff --git a/.env.example b/.env.example index c839d254b..1005ad208 100644 --- a/.env.example +++ b/.env.example @@ -60,13 +60,13 @@ GITLAB_BASE_URI=false DISCORD_APP_ID=false DISCORD_APP_SECRET=false -# External services such as Gravatar and Draw.IO + +# Disable default services such as Gravatar and Draw.IO DISABLE_EXTERNAL_SERVICES=false -# Default GRAVATAR_URL set to Gravatar service -GRAVATAR_URL=false -# To use a different service to get user's avatar like libravatar -# Possible placeholders: %{hash} %{size} %{email} -#GRAVATAR_URL=https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon +# Use custom avatar service, Sets fetch URL +# Possible placeholders: ${hash} ${size} ${email} +# If set, Avatars will be fetched regardless of DISABLE_EXTERNAL_SERVICES option. +# AVATAR_URL=https://seccdn.libravatar.org/avatar/${hash}?s=${size}&d=identicon # LDAP Settings LDAP_SERVER=false diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index abff7c641..d436ab8eb 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -85,9 +85,7 @@ class UserRepo { $user = $this->create($data, $verifyEmail); $this->attachDefaultRole($user); - - // Get avatar from gravatar and save - $this->downloadGravatarToUserAvatar($user); + $this->downloadAndAssignUserAvatar($user); return $user; } @@ -238,25 +236,24 @@ class UserRepo } /** - * Get a gravatar image for a user and set it as their avatar. - * Does not run if gravatar disabled in config. + * Get an avatar image for a user and set it as their avatar. + * Returns early if avatars disabled or not set in config. * @param User $user * @return bool */ - public function downloadGravatarToUserAvatar(User $user) + public function downloadAndAssignUserAvatar(User $user) { - // Get avatar from gravatar and save - if (!config('services.gravatar')) { + if (!Images::avatarFetchEnabled()) { return false; } try { - $avatar = Images::saveUserGravatar($user, config('services.gravatar_url')); + $avatar = Images::saveUserAvatar($user); $user->avatar()->associate($avatar); $user->save(); return true; } catch (Exception $e) { - \Log::error('Failed to save user gravatar image'); + \Log::error('Failed to save user avatar image'); return false; } } diff --git a/app/Console/Commands/CreateAdmin.php b/app/Console/Commands/CreateAdmin.php index 6bfc54469..90c1ddb1c 100644 --- a/app/Console/Commands/CreateAdmin.php +++ b/app/Console/Commands/CreateAdmin.php @@ -76,7 +76,7 @@ class CreateAdmin extends Command $user = $this->userRepo->create(['email' => $email, 'name' => $name, 'password' => $password]); $this->userRepo->attachSystemRole($user, 'admin'); - $this->userRepo->downloadGravatarToUserAvatar($user); + $this->userRepo->downloadAndAssignUserAvatar($user); $user->email_confirmed = true; $user->save(); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 5f5c8365e..24f8b67cb 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -92,7 +92,7 @@ class UserController extends Controller $user->roles()->sync($roles); } - $this->userRepo->downloadGravatarToUserAvatar($user); + $this->userRepo->downloadAndAssignUserAvatar($user); return redirect('/settings/users'); } diff --git a/app/Uploads/ImageService.php b/app/Uploads/ImageService.php index b65a476f4..d5f4068ef 100644 --- a/app/Uploads/ImageService.php +++ b/app/Uploads/ImageService.php @@ -279,30 +279,51 @@ class ImageService extends UploadService } /** - * Save a gravatar image and set a the profile image for a user. + * Save an avatar image from an external service. * @param \BookStack\Auth\User $user - * @param null|string $gravatarUrl * @param int $size - * @return mixed + * @return Image * @throws Exception */ - public function saveUserGravatar(User $user, $gravatarUrl, $size = 500) + public function saveUserAvatar(User $user, $size = 500) { - if (!is_string($gravatarUrl) || empty($gravatarUrl)) { - $gravatarUrl = 'https://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon'; - } + $avatarUrl = $this->getAvatarUrl(); $email = strtolower(trim($user->email)); - $gravatarUrl = str_replace('%{hash}', md5($email), $gravatarUrl); - $gravatarUrl = str_replace('%{size}', $size, $gravatarUrl); - $gravatarUrl = str_replace('%{email}', urlencode($email), $gravatarUrl); - $imageName = str_replace(' ', '-', $user->name . '-gravatar.png'); - $image = $this->saveNewFromUrl($gravatarUrl, 'user', $imageName); + + $replacements = [ + '${hash}' => md5($email), + '${size}' => $size, + '${email}' => urlencode($email), + ]; + + $userAvatarUrl = strtr($avatarUrl, $replacements); + $imageName = str_replace(' ', '-', $user->name . '-avatar.png'); + $image = $this->saveNewFromUrl($userAvatarUrl, 'user', $imageName); $image->created_by = $user->id; $image->updated_by = $user->id; $image->save(); + return $image; } + /** + * Check if fetching external avatars is enabled. + * @return bool + */ + public function avatarFetchEnabled() + { + $fetchUrl = $this->getAvatarUrl(); + return is_string($fetchUrl) && strpos($fetchUrl, 'http') === 0; + } + + /** + * Get the URL to fetch avatars from. + * @return string|mixed + */ + protected function getAvatarUrl() + { + return trim(config('services.avatar_url')); + } /** * Delete gallery and drawings that are not within HTML content of pages or page revisions. diff --git a/config/services.php b/config/services.php index 310ea295f..7b9cf4e74 100644 --- a/config/services.php +++ b/config/services.php @@ -16,11 +16,16 @@ return [ // Single option to disable non-auth external services such as Gravatar and Draw.io 'disable_services' => env('DISABLE_EXTERNAL_SERVICES', false), - 'gravatar' => env('GRAVATAR', !env('DISABLE_EXTERNAL_SERVICES', false)), + + // Draw.io integration active 'drawio' => env('DRAWIO', !env('DISABLE_EXTERNAL_SERVICES', false)), - 'gravatar_url' => env('GRAVATAR_URL', false), + // URL for fetching avatars + 'avatar_url' => env('AVATAR_URL', + env('DISABLE_EXTERNAL_SERVICES', false) ? false : 'https://www.gravatar.com/avatar/${hash}?s=${size}&d=identicon' + ), + // Callback URL for social authentication methods 'callback_url' => env('APP_URL', false), 'mailgun' => [