Skip to content
Draft
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 @@ -22,7 +22,8 @@ open class EditorConfiguration constructor(
val cookies: Map<String, String>,
val enableAssetCaching: Boolean = false,
val cachedAssetHosts: Set<String> = emptySet(),
val editorAssetsEndpoint: String? = null
val editorAssetsEndpoint: String? = null,
val assetLoaderDomain: String? = null
): Parcelable {
companion object {
@JvmStatic
Expand All @@ -48,6 +49,7 @@ open class EditorConfiguration constructor(
private var enableAssetCaching: Boolean = false
private var cachedAssetHosts: Set<String> = emptySet()
private var editorAssetsEndpoint: String? = null
private var assetLoaderDomain: String? = null

fun setTitle(title: String) = apply { this.title = title }
fun setContent(content: String) = apply { this.content = content }
Expand All @@ -67,6 +69,7 @@ open class EditorConfiguration constructor(
fun setEnableAssetCaching(enableAssetCaching: Boolean) = apply { this.enableAssetCaching = enableAssetCaching }
fun setCachedAssetHosts(cachedAssetHosts: Set<String>) = apply { this.cachedAssetHosts = cachedAssetHosts }
fun setEditorAssetsEndpoint(editorAssetsEndpoint: String?) = apply { this.editorAssetsEndpoint = editorAssetsEndpoint }
fun setAssetLoaderDomain(assetLoaderDomain: String?) = apply { this.assetLoaderDomain = assetLoaderDomain }

fun build(): EditorConfiguration = EditorConfiguration(
title = title,
Expand All @@ -86,7 +89,8 @@ open class EditorConfiguration constructor(
cookies = cookies,
enableAssetCaching = enableAssetCaching,
cachedAssetHosts = cachedAssetHosts,
editorAssetsEndpoint = editorAssetsEndpoint
editorAssetsEndpoint = editorAssetsEndpoint,
assetLoaderDomain = assetLoaderDomain
)
}

Expand Down Expand Up @@ -114,6 +118,7 @@ open class EditorConfiguration constructor(
if (enableAssetCaching != other.enableAssetCaching) return false
if (cachedAssetHosts != other.cachedAssetHosts) return false
if (editorAssetsEndpoint != other.editorAssetsEndpoint) return false
if (assetLoaderDomain != other.assetLoaderDomain) return false

return true
}
Expand All @@ -137,6 +142,7 @@ open class EditorConfiguration constructor(
result = 31 * result + enableAssetCaching.hashCode()
result = 31 * result + cachedAssetHosts.hashCode()
result = 31 * result + (editorAssetsEndpoint?.hashCode() ?: 0)
result = 31 * result + (assetLoaderDomain?.hashCode() ?: 0)
return result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ import org.json.JSONException
import org.json.JSONObject
import java.util.Locale

const val ASSET_URL = "https://appassets.androidplatform.net/assets/index.html"
const val ASSET_URL_REMOTE = "https://appassets.androidplatform.net/assets/remote.html"
const val DEFAULT_ASSET_DOMAIN = "appassets.androidplatform.net"
const val ASSET_PATH_INDEX = "/assets/index.html"
const val ASSET_PATH_REMOTE = "/assets/remote.html"

class GutenbergView : WebView {
private var isEditorLoaded = false
private var didFireEditorLoaded = false
private var assetLoader = WebViewAssetLoader.Builder()
.addPathHandler("/assets/", AssetsPathHandler(this.context))
.build()
private lateinit var assetLoader: WebViewAssetLoader
private lateinit var assetDomain: String
private var configuration: EditorConfiguration = EditorConfiguration.builder().build()

private val handler = Handler(Looper.getMainLooper())
Expand Down Expand Up @@ -131,7 +131,7 @@ class GutenbergView : WebView {
): WebResourceResponse? {
if (request.url == null) {
return super.shouldInterceptRequest(view, request)
} else if (request.url.host?.contains("appassets.androidplatform.net") == true) {
} else if (request.url.host == assetDomain) {
return assetLoader.shouldInterceptRequest(request.url)
} else if (requestInterceptor.canIntercept(request)) {
return requestInterceptor.handleRequest(request)
Expand Down Expand Up @@ -164,7 +164,7 @@ class GutenbergView : WebView {
}

// Allow asset URLs
if (url.host == Uri.parse(ASSET_URL).host || url.host == Uri.parse(ASSET_URL_REMOTE).host) {
if (url.host == assetDomain) {
return false
}

Expand Down Expand Up @@ -245,6 +245,15 @@ class GutenbergView : WebView {
fun start(configuration: EditorConfiguration) {
this.configuration = configuration

// Set up asset loader domain
assetDomain = configuration.assetLoaderDomain ?: DEFAULT_ASSET_DOMAIN

// Initialize asset loader with configured domain
assetLoader = WebViewAssetLoader.Builder()
.setDomain(assetDomain)
.addPathHandler("/assets/", AssetsPathHandler(this.context))
.build()

// Set up asset caching if enabled
if (configuration.enableAssetCaching) {
val library = EditorAssetsLibrary(context, configuration)
Expand All @@ -262,15 +271,15 @@ class GutenbergView : WebView {
} else if (BuildConfig.GUTENBERG_EDITOR_URL.isNotEmpty()) {
BuildConfig.GUTENBERG_EDITOR_URL
} else if (configuration.plugins) {
ASSET_URL_REMOTE
"https://$assetDomain$ASSET_PATH_REMOTE"
} else {
ASSET_URL
"https://$assetDomain$ASSET_PATH_INDEX"
}

WebStorage.getInstance().deleteAllData()
this.clearCache(true)
// All cookies are third-party cookies because the root of this document
// lives under `https://appassets.androidplatform.net`
// lives under the configured asset domain (e.g., `https://appassets.androidplatform.net`)
CookieManager.getInstance().setAcceptThirdPartyCookies(this, true);

// Erase all local cookies before loading the URL – we don't want to persist
Expand All @@ -293,6 +302,7 @@ class GutenbergView : WebView {

val gbKitConfig = """
window.GBKit = {
"siteURL": "${configuration.siteURL}",
"siteApiRoot": "${configuration.siteApiRoot}",
"siteApiNamespace": ${configuration.siteApiNamespace.joinToString(",", "[", "]") { "\"$it\"" }},
"namespaceExcludedPaths": ${configuration.namespaceExcludedPaths.joinToString(",", "[", "]") { "\"$it\"" }},
Expand Down
80 changes: 80 additions & 0 deletions src/utils/ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Internal dependencies
*/
import { getGBKit } from './bridge';
import { warn, debug } from './logger';

/**
* GutenbergKit lacks authentication cookies required for AJAX requests.
* This configures a root URL and authentication header for AJAX requests.
*
* @return {void}
*/
export function configureAjax() {
window.wp = window.wp || {};
window.wp.ajax = window.wp.ajax || {};
window.wp.ajax.settings = window.wp.ajax.settings || {};

const { siteURL, authHeader } = getGBKit();
configureAjaxUrl( siteURL );
configureAjaxAuth( authHeader );
}

function configureAjaxUrl( siteURL ) {
if ( ! siteURL ) {
warn( 'Unable to configure AJAX URL without siteURL' );
return;
}

// Global used within WordPress admin pages
window.ajaxurl = `${ siteURL }/wp-admin/admin-ajax.php`;
// Global used by WordPress' JavaScript API
window.wp.ajax.settings.url = `${ siteURL }/wp-admin/admin-ajax.php`;

debug( 'AJAX URL configured' );
}

function configureAjaxAuth( authHeader ) {
if ( ! authHeader ) {
warn( 'Unable to configure AJAX auth without authHeader' );
return;
}

window.jQuery?.ajaxSetup( {
headers: {
Authorization: authHeader,
},
} );

const originalSend = window.wp.ajax.send;
window.wp.ajax.send = function ( options ) {
const originalBeforeSend = options.beforeSend;

options.beforeSend = function ( xhr ) {
xhr.setRequestHeader( 'Authorization', authHeader );

if ( typeof originalBeforeSend === 'function' ) {
originalBeforeSend( xhr );
}
};

return originalSend.call( this, options );
};

const originalPost = window.wp.ajax.post;
window.wp.ajax.post = function ( options ) {
const originalBeforeSend = options.beforeSend;

options.beforeSend = function ( xhr ) {
xhr.setRequestHeader( 'Authorization', authHeader );

if ( typeof originalBeforeSend === 'function' ) {
originalBeforeSend( xhr );
}
};

return originalPost.call( this, options );
};

debug( 'AJAX auth configured' );
}
Loading