diff --git a/.env.example b/.env.example index 11dafa2ab..1005ad208 100644 --- a/.env.example +++ b/.env.example @@ -60,8 +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 +# 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 7c88badb8..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); + $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 f109db600..d5f4068ef 100644 --- a/app/Uploads/ImageService.php +++ b/app/Uploads/ImageService.php @@ -279,24 +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 int $size - * @return mixed + * @return Image * @throws Exception */ - public function saveUserGravatar(User $user, $size = 500) + public function saveUserAvatar(User $user, $size = 500) { - $emailHash = md5(strtolower(trim($user->email))); - $url = 'https://www.gravatar.com/avatar/' . $emailHash . '?s=' . $size . '&d=identicon'; - $imageName = str_replace(' ', '-', $user->name . '-gravatar.png'); - $image = $this->saveNewFromUrl($url, 'user', $imageName); + $avatarUrl = $this->getAvatarUrl(); + $email = strtolower(trim($user->email)); + + $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 ba1648891..7b9cf4e74 100644 --- a/config/services.php +++ b/config/services.php @@ -16,10 +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)), + // 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' => [