Kostiantyn Petlia
Forum Replies Created
-
Thank you for fast implementation of the changes.
Forum: Plugins
In reply to: [Web Stories] Content Security Policy and the plugin scriptsFirst of all, thank you for your fast support, Pascal.
I’m going to test the site well, but currently, everything works well.
I think the next information can be useful for other developers.
Conflict with the web stories PHP buffer
The main problem with the PHP buffer was that the web stories’s buffer was opened after my (‘init, 0’) and it is closed by WordPress in the next line:/wordpress/wp-includes/default-filters.php line 412: add_action( 'shutdown', 'wp_ob_end_flush_all', 1 );
As a result, any priority of ‘shutdown’ higher than 1 didn’t work for my closing method. At that moment all buffers are flushed already. Any priority of ‘shutdown’ less than 1 breaks web stories, because my code closes the web stories buffer (not mine). So, I decided to use your approach and set a callback function for my buffering:ob_start([self::class, 'preparePageBufferToOutput']);
On ‘shutdown, 1’ WordPress closes all open buffers: the web stories buffer and mine. No conflicts!
CSP header, CSP meta, and scripts’s nonces are present, but web stories still throw a CSP blocking error
It was extraordinary. Everything was present and set well, but there were two CSP errors in the Chrome Console. Despite this, it seemed web stories worked well… Anyway, I figured out where was a problem:<link rel="preload" as="script" >
When you add the CSP nonce to this link those errors disappear. (Nonce to a link tag? Why? It’s still a mystery to me ?? ) So, here is a modified version of your example:if (interface_exists(Transformer::class)) {
class WebStoryNonceTransformer implements Transformer
{
/**
* Applies nonce addition to scripts and preload links in the provided DOM document.
*
* @param Document $document DOM document to apply the transformations to.
* @param ErrorCollection $errors Collection of errors that are collected during transformation.
*
* @return void
*/
public function transform(Document $document, ErrorCollection $errors): void
{
$nonce = PolicyBuilder::getTheNonce();
$xpath = $document->xpath;
$query = '//script[not(@type) or @type="module"] | '
. '//link[@rel="preload" and @as="script"] | '
. '//link[@rel="modulepreload"]';
$elements = $xpath->query($query);
if ($elements instanceof DOMNodeList) {
foreach ($elements as $element) {
/** @var DOMElement $element */
$element->setAttribute('nonce', $nonce);
}
}
}
}
}I hope I won’t have to bother you again.
Forum: Plugins
In reply to: [Web Stories] Content Security Policy and the plugin scriptsYeap, our CSP plugin breaks Web Stories. When I disable it web stories work. But I need to understand where there is a conflict and why it is. It’s not so complicated plugin with the page buffering from ‘init, 0’ to ‘shutdown, 0’ and changing HTTP headers right before the buffered page outputting.
Do web stories do some work after the ‘shutdown, 0’ hook? According to not compressed style, it looks possible… The order of execution that I can see:- ‘init, 0’: ob_start();
- your transform() code;
- ‘shutdown, 0’: $page = ob_get_clean(); … echo $page;
I’m going to dive deeper into it and happy with any suggestions.
Forum: Plugins
In reply to: [Web Stories] Content Security Policy and the plugin scriptsHere is the shortcode:
[web_stories title=”true” excerpt=”false” author=”false” date=”false” archive_link=”true” archive_link_label=”View all” circle_size=”150″ sharp_corners=”false” image_alignment=”left” number_of_columns=”1″ number_of_stories=”5″ order=”DESC” orderby=”post_date” view=”carousel” /]
The shortcode outputs web stories on the
https://localhost:8000/insights/
blog page. On this page I can see 4 CSP errors. All them have the same link on the first story in the carousel:https://localhost:8000/web-stories/all-you-need-to-knowabout-iomt/#visibilityState=prerender&origin=http%3A%2F%2Flocalhost%3A8000&showStoryUrlInfo=0&storyPlayer=v0&cap=swipe
Scripts:https://cdn.ampproject.org/v0.js
&https://cdn.ampproject.org/v0/amp-story-1.0.js.
It seems the same two CSP errors were triggered twice: 2+2 = 4 errors.When I click (or open in a new tab) on the first story on the carousel I see the color-filled screen and the story excerpt super small text and the same 4 CSP errors, but with URL:
https://localhost:8000/web-stories/all-you-need-to-knowabout-iomt/
.So, the issue is the same for the blog page and the single story page. But the blog page looks normal at least.
Let me provide a bit more details about the CSP implementation.
How it currently works:- we don’t use CSP on the server level (.htaccess);
- we add our CSP on the WP/PHP level based on standard WP functions and filters for JS scripts;
- we use the whole PHP page buffering and build the dynamic SCP (start on the ‘init’ hook), calculate hashes and add the nonce to scripts, update HTTP headers with the CSP, add <meta> with the CSP to <head>, and output the page on the ‘shutdown’ WP action (right after the mentioned our
sendHeaders()
method that updates headers with the CSP);
The error message example:
“Refused to load the script https://cdn.ampproject.org/v0.js because it violates the following Content Security Policy directive: “script-src ‘self’ ‘strict-dynamic’ {domains} ‘nonce-2295cb6ff3′”. Note that ‘strict-dynamic’ is present, so host-based allowlisting is disabled. Note that ‘script-src-elem’ was not explicitly set, so ‘script-src’ is used as a fallback.”Important:
When I use a dirty fix withstr_replace()
before buffer outputting on the $page everything works well.
I’m logged and the WP-Rocket cache doesn’t work. I don’t remember that we changed Web Stories functionality somehow; only styles.Debug:
$document in your method has:<$cript async="" src="https://cdn.ampproject.org/v0.mjs" type="module" crossorigin="anonymous" nonce="2295cb6ff3">
The buffered $page on the echo moment has:<$cript async="" src="https://cdn.ampproject.org/v0.js">
Forum: Plugins
In reply to: [Web Stories] Content Security Policy and the plugin scriptsCould you help me a bit more?
I’ve implemented this transformer functionality. Firstly I changed it in a more OOP way for my plugin structure, but later I just put your code “as is” in functions.php for debug purposes.
On the blog page (
https://localhost:8000/insights/
) I have a Web Stories shortcode and can see 4 stories. It’s thediv.web-stories-list
. I see CSP errors they referrer tohttps://localhost:8000/web-stories/all-you-need-to-knowabout-iomt/
. It’siframe.story-player-iframe
with src:https://localhost:8000/web-stories/all-you-need-to-knowabout-iomt/#visibilityState=prerender&origin=http%3A%2F%2Flocalhost%3A8000&showStoryUrlInfo=0&storyPlayer=v0&cap=swipe
.The issue: Your code works, $document is updated, but an iframe story page is pretty different. It’s strange…
- During debugging, I can see the updated scripts with the nonce (I used
$updatedHtml = $document->saveHTML();
) in our transform() method. So, your code applies the nonce to scripts in$document
. - But on the frontend (the same on the outputting of the page buffer
self::sendHeaders($headers); echo $page;
) I can see a partially different HTML page: scripts are without the nonce;style
tag with theamp-custom
attribute is NOT compressed; my <meta> CSP is present (I insert it before page outputting), but it is absent in the #1, etc.
Could you explain it and advise me on how to fix it? It seems I don’t understand well how web stories are rendered.
- This reply was modified 2 months, 1 week ago by Kostiantyn Petlia.
Forum: Plugins
In reply to: [Web Stories] Content Security Policy and the plugin scriptsThank you for fast answer and the code example. I’m going to implement it and back with feedback.
Update
Emails are not sent.
Theglobal $phpmailer;
returnsnull
inwp_mail()
and creates a new instance$phpmailer = new PHPMailer\PHPMailer\PHPMailer( true );
In DB in the wp_option table, I can see
mailjet_apikey
&mailjet_apisecret
. TheMailjetApi::isValidAPICredentials()
returns true during debugging.- This reply was modified 1 year, 2 months ago by Kostiantyn Petlia. Reason: Adding a bit more info