Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Font upload: check file mods permission and fall back to remote font urls #59104

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,14 @@ public function create_item( $request ) {
$settings = $request->get_param( 'font_face_settings' );
$file_params = $request->get_file_params();

if ( ! empty( $file_params ) && ! $this->can_upload_fonts() ) {
return new WP_Error(
'rest_cannot_upload_fonts',
__( 'You are not allowed to upload font files.', 'gutenberg' ),
array( 'status' => 403 )
);
}

// Check that the necessary font face properties are unique.
$query = new WP_Query(
array(
Expand Down Expand Up @@ -903,6 +911,18 @@ public function handle_font_file_upload_error( $file, $message ) {
return new WP_Error( $code, $message, array( 'status' => $status ) );
}

/**
* Checks if fonts can be uploaded to the site.
*
* @since 6.5.0
*
* @return bool Whether font assets can be upload.
*/
protected function can_upload_fonts() {
$fonts_dir = wp_get_font_dir()['path'];
return wp_is_file_mod_allowed( 'can_upload_fonts' ) && wp_is_writable( $fonts_dir );
}
Comment on lines +921 to +924
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use a current_user_can() check rather than calling wp_is_file_mod_allowed() directly. This will allow plugin developers to avoid having to reproduce this code each time.

The read_post cap is inconsistent and can lead to some messy code as a result.


/**
* Returns relative path to an uploaded font file.
*
Expand Down
9 changes: 9 additions & 0 deletions lib/compat/wordpress-6.5/fonts/fonts.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,15 @@ function wp_get_font_dir( $defaults = array() ) {
}
}

function gutenberg_font_upload_settings( $settings ) {
$fonts_dir = wp_get_font_dir()['path'];

$settings['fontUploadEnabled'] = wp_is_file_mod_allowed( 'can_upload_fonts' ) && wp_is_writable( $fonts_dir );

return $settings;
}
add_filter( 'block_editor_settings_all', 'gutenberg_font_upload_settings' );

// @core-merge: Filters should go in `src/wp-includes/default-filters.php`,
// functions in a general file for font library.
if ( ! function_exists( '_wp_after_delete_font_family' ) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
import { debounce } from '@wordpress/compose';
import { sprintf, __, _x } from '@wordpress/i18n';
import { search, closeSmall } from '@wordpress/icons';
import { store as editorStore } from '@wordpress/editor';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
Expand Down Expand Up @@ -161,13 +163,13 @@ function FontCollection( { slug } ) {
setFontsToInstall( [] );
};

const handleInstall = async () => {
const handleInstall = async ( shouldUpload = true ) => {
setNotice( null );

const fontFamily = fontsToInstall[ 0 ];

try {
if ( fontFamily?.fontFace ) {
if ( fontFamily?.fontFace && shouldUpload ) {
await Promise.all(
fontFamily.fontFace.map( async ( fontFace ) => {
if ( fontFace.src ) {
Expand Down Expand Up @@ -398,12 +400,17 @@ function PaginationFooter( { page, totalPages, setPage } ) {

function InstallFooter( { handleInstall, isDisabled } ) {
const { isInstalling } = useContext( FontLibraryContext );
const fontUploadEnabled = useSelect(
( select ) =>
select( editorStore ).getEditorSettings().fontUploadEnabled,
[]
);

return (
<Flex justify="flex-end">
<Button
variant="primary"
onClick={ handleInstall }
onClick={ () => handleInstall( fontUploadEnabled ) }
isBusy={ isInstalling }
disabled={ isDisabled || isInstalling }
__experimentalIsFocusable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
privateApis as componentsPrivateApis,
} from '@wordpress/components';
import { useContext } from '@wordpress/element';
import { store as editorStore } from '@wordpress/editor';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
Expand All @@ -24,12 +26,13 @@ const DEFAULT_TABS = [
id: 'installed-fonts',
title: __( 'Library' ),
},
{
id: 'upload-fonts',
title: __( 'Upload' ),
},
];

const UPLOAD_TAB = {
id: 'upload-fonts',
title: __( 'Upload' ),
};

const tabsFromCollections = ( collections ) =>
collections.map( ( { slug, name } ) => ( {
id: slug,
Expand All @@ -44,9 +47,15 @@ function FontLibraryModal( {
defaultTabId = 'installed-fonts',
} ) {
const { collections, setNotice } = useContext( FontLibraryContext );
const fontUploadEnabled = useSelect(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will still need a canUser( 'create', 'font-families' ); check to account for developers disabling the creating of the post type via roles and caps. As will delete post, edit post, etc.

add_filter( 'register_post_type_args', function( $args, $name ) {
  // if post type == font-families, font-faces
  $args['capabilities']['create_posts'] = 'do_not_allow';
  return $args;
}, 10, 2 ); 

( select ) =>
select( editorStore ).getEditorSettings().fontUploadEnabled,
[]
);

const tabs = [
...DEFAULT_TABS,
...( fontUploadEnabled ? [ UPLOAD_TAB ] : [] ),
...tabsFromCollections( collections || [] ),
];

Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/store/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SETTINGS_DEFAULTS } from '@wordpress/block-editor';
* @property {boolean} richEditingEnabled Whether rich editing is enabled or not
* @property {boolean} codeEditingEnabled Whether code editing is enabled or not
* @property {boolean} fontLibraryEnabled Whether the font library is enabled or not.
* @property {boolean} fontUploadEnabled Whether uploading fonts in the font library is enabled or not.
* @property {boolean} enableCustomFields Whether the WordPress custom fields are enabled or not.
* true = the user has opted to show the Custom Fields panel at the bottom of the editor.
* false = the user has opted to hide the Custom Fields panel at the bottom of the editor.
Expand All @@ -28,6 +29,7 @@ export const EDITOR_SETTINGS_DEFAULTS = {
richEditingEnabled: true,
codeEditingEnabled: true,
fontLibraryEnabled: true,
fontUploadEnabled: true,
enableCustomFields: undefined,
defaultRenderingMode: 'post-only',
};
Loading