-
Notifications
You must be signed in to change notification settings - Fork 448
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
feat: Add WPGraphQL Extensions Page to the WordPress admin #3188
Conversation
This reverts commit 33fdf01.
</div> | ||
<div className="action-links"> | ||
<ul className="plugin-action-buttons"> | ||
{host.includes('wordpress.org') && ( |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization High
wordpress.org
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix AI about 1 month ago
To fix the problem, we need to ensure that the host of the URL is explicitly checked against a whitelist of allowed hosts. This involves parsing the URL to extract the host and then comparing it against a predefined list of allowed hosts. This approach prevents malicious URLs from bypassing the check by embedding the allowed host in unexpected locations.
- Parse the URL to extract the host.
- Define a whitelist of allowed hosts.
- Check if the parsed host is in the whitelist.
- Update the relevant code to use this new check.
-
Copy modified lines R42-R44 -
Copy modified line R74 -
Copy modified line R87
@@ -41,3 +41,5 @@ | ||
|
||
const host = new URL(plugin.plugin_url).host; | ||
const url = new URL(plugin.plugin_url); | ||
const host = url.host; | ||
const allowedHosts = ['wordpress.org', 'github.com']; | ||
const { buttonText, buttonDisabled } = getButtonDetails(host, plugin.plugin_url, isInstalled, isActive, installing, activating); | ||
@@ -71,3 +73,3 @@ | ||
<ul className="plugin-action-buttons"> | ||
{host.includes('wordpress.org') && ( | ||
{allowedHosts.includes(host) && host === 'wordpress.org' && ( | ||
<li> | ||
@@ -84,3 +86,3 @@ | ||
)} | ||
{host.includes('github.com') && ( | ||
{allowedHosts.includes(host) && host === 'github.com' && ( | ||
<li> |
- re-built the react app
refactor: validate extensions with PHP
feat: submit an extension criteria and validation
# Conflicts: # composer.lock # package-lock.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR diff size of 10733 lines exceeds the maximum allowed for the inline comments feature.
- phpcs cleanup
…l-acf feat: add WPGraphQL for ACF to the extensions page
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR diff size of 10731 lines exceeds the maximum allowed for the inline comments feature.
…l-yoast-seo-addon feat: add the WPGraphQL Yoast SEO addon to the extensions page
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR diff size of 10742 lines exceeds the maximum allowed for the inline comments feature.
# Conflicts: # build/app.asset.php # build/app.js # composer.lock # package-lock.json # webpack.config.js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR diff size of 11271 lines exceeds the maximum allowed for the inline comments feature.
@@ -0,0 +1 @@ | |||
(()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var a in n)e.o(n,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:n[a]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.element,n=window.React,a=window.wp.i18n,i=window.wp.components,s=window.wp.apiFetch;var l=e.n(s);const r=window.ReactJSXRuntime,o=({plugin:e})=>{const{installing:s,activating:o,status:p,error:c,installPlugin:u,activatePlugin:d}=((e,t)=>{const[i,s]=(0,n.useState)(!1),[r,o]=(0,n.useState)(!1),[p,c]=(0,n.useState)(""),[u,d]=(0,n.useState)(""),w=(e,t="")=>{c(e),d(t)},h=async(n=t)=>{if(o(!0),w((0,a.__)("Activating...","wp-graphql")),!n){let t=new URL(e).pathname.split("/").filter(Boolean).pop();n=`${t}/${t}.php`}try{const t=await l()({path:`/wp/v2/plugins/${n}`,method:"PUT",data:{status:"active"},headers:{"X-WP-Nonce":wpgraphqlExtensions.nonce}});if("active"===t.status)return w((0,a.__)("Active","wp-graphql")),window.wpgraphqlExtensions.extensions=window.wpgraphqlExtensions.extensions.map((t=>t.plugin_url===e?{...t,installed:!0,active:!0}:t)),!0;throw t.message.includes("Plugin file does not exist")?new Error((0,a.__)("Plugin file does not exist","wp-graphql")):new Error((0,a.__)("Activation failed","wp-graphql"))}catch(e){throw w((0,a.__)("Activation failed","wp-graphql"),e.message||(0,a.__)("Activation failed","wp-graphql")),e}finally{s(!1),o(!1)}};return{installing:i,activating:r,status:p,error:u,installPlugin:async()=>{s(!0),w((0,a.__)("Installing...","wp-graphql"));let n=new URL(e).pathname.split("/").filter(Boolean).pop();try{if("inactive"!==(await l()({path:"/wp/v2/plugins",method:"POST",data:{slug:n,status:"inactive"},headers:{"X-WP-Nonce":wpgraphqlExtensions.nonce}})).status)throw new Error((0,a.__)("Installation failed","wp-graphql"));await h(t)}catch(e){if(!e.message.includes("destination folder already exists"))throw w((0,a.__)("Installation failed","wp-graphql"),e.message||(0,a.__)("Installation failed","wp-graphql")),s(!1),e;await h(t)}},activatePlugin:h}})(e.plugin_url,e.plugin_path),[w,h]=(0,t.useState)(e.installed),[g,_]=(0,t.useState)(e.active),[m,x]=(0,t.useState)(!0);(0,t.useEffect)((()=>{h(e.installed),_(e.active)}),[e]);const b=new URL(e.plugin_url).host,{buttonText:f,buttonDisabled:v}=((e,t,n,i,s,l,r)=>{let o,p=!1,c=null;const u=e=>()=>window.open(e,"_blank");if(s)o=(0,a.__)("Installing...","wp-graphql"),p=!0;else if(l)o=(0,a.__)("Activating...","wp-graphql"),p=!0;else if(i)o=(0,a.__)("Active","wp-graphql"),p=!0;else if(n)o=(0,a.__)("Activate","wp-graphql"),c=r;else{const e=new URL(t).hostname.toLowerCase();switch(!0){case/github\.com$/.test(e):o=(0,a.__)("View on GitHub","wp-graphql"),c=u(t);break;case/bitbucket\.org$/.test(e):o=(0,a.__)("View on Bitbucket","wp-graphql"),c=u(t);break;case/gitlab\.com$/.test(e):o=(0,a.__)("View on GitLab","wp-graphql"),c=u(t);break;case/wordpress\.org$/.test(e):o=(0,a.__)("Install & Activate","wp-graphql"),c=r;break;default:o=(0,a.__)("View Plugin","wp-graphql"),c=u(t)}}return{buttonText:o,buttonDisabled:p,buttonOnClick:c}})(0,e.plugin_url,w,g,s,o),q=({author:e})=>e&&e.name&&e.homepage?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("em",{children:"By "}),(0,r.jsx)("cite",{children:(0,r.jsx)("a",{href:e.homepage,target:"_blank",rel:"noopener noreferrer",children:e.name})},e.homepage)]}):null;return(0,r.jsxs)("div",{className:"plugin-card",children:[(0,r.jsxs)("div",{className:"plugin-card-top",children:[(0,r.jsxs)("div",{className:"name column-name",children:[(0,r.jsx)("h2",{children:e.name}),(0,r.jsx)(q,{author:e.author}),e.experiment&&(0,r.jsx)("em",{className:"plugin-experimental",children:"(experimental)"})]}),(0,r.jsx)("div",{className:"action-links",children:(0,r.jsxs)("ul",{className:"plugin-action-buttons",children:[b.includes("wordpress.org")&&(0,r.jsx)("li",{children:(0,r.jsxs)("button",{type:"button",className:"button "+(g?"button-disabled":"button-primary"),disabled:v,onClick:async()=>{const t=w,n=g;try{w?(await d(e.plugin_path),_(!0)):(await u(),h(!0),_(!0))}catch(e){h(t),_(n)}finally{window.wpgraphqlExtensions.extensions=window.wpgraphqlExtensions.extensions.map((t=>t.plugin_url===e.plugin_url?{...t,installed:w,active:g}:t))}},children:[f,(s||o)&&(0,r.jsx)(i.Spinner,{})]})}),b.includes("github.com")&&(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:e.plugin_url,target:"_blank",rel:"noopener noreferrer",className:"button button-secondary",children:(0,a.__)("View on GitHub","wp-graphql")})}),e.support_url&&(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:e.support_url,target:"_blank",rel:"noopener noreferrer",className:"thickbox open-plugin-details-modal",children:(0,a.__)("Get Support","wp-graphql")})}),e.settings_url&&(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:e.settings_url,children:(0,a.__)("Settings","wp-graphql")})})]})}),(0,r.jsx)("div",{className:"desc column-description",children:(0,r.jsx)("p",{children:e.description})})]}),c&&m&&(0,r.jsx)(i.Notice,{status:"error",isDismissible:!0,onRemove:()=>x(!1),children:c})]})},p=()=>{const[e,t]=(0,n.useState)([]);return(0,n.useEffect)((()=>{window.wpgraphqlExtensions&&window.wpgraphqlExtensions.extensions&&t(window.wpgraphqlExtensions.extensions)}),[]),(0,r.jsx)("div",{className:"wp-clearfix",children:(0,r.jsx)("div",{className:"plugin-cards",children:e.map((e=>(0,r.jsx)(o,{plugin:e},e.plugin_url)))})})};document.addEventListener("DOMContentLoaded",(()=>{const e=document.getElementById("wpgraphql-extensions");e&&(0,t.createRoot)(e).render((0,t.createElement)(p))}))})(); |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization High
wordpress.org
Copilot Autofix AI 11 days ago
Copilot could not generate an autofix suggestion
Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.
@@ -0,0 +1 @@ | |||
(()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var a in n)e.o(n,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:n[a]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.element,n=window.React,a=window.wp.i18n,i=window.wp.components,s=window.wp.apiFetch;var l=e.n(s);const r=window.ReactJSXRuntime,o=({plugin:e})=>{const{installing:s,activating:o,status:p,error:c,installPlugin:u,activatePlugin:d}=((e,t)=>{const[i,s]=(0,n.useState)(!1),[r,o]=(0,n.useState)(!1),[p,c]=(0,n.useState)(""),[u,d]=(0,n.useState)(""),w=(e,t="")=>{c(e),d(t)},h=async(n=t)=>{if(o(!0),w((0,a.__)("Activating...","wp-graphql")),!n){let t=new URL(e).pathname.split("/").filter(Boolean).pop();n=`${t}/${t}.php`}try{const t=await l()({path:`/wp/v2/plugins/${n}`,method:"PUT",data:{status:"active"},headers:{"X-WP-Nonce":wpgraphqlExtensions.nonce}});if("active"===t.status)return w((0,a.__)("Active","wp-graphql")),window.wpgraphqlExtensions.extensions=window.wpgraphqlExtensions.extensions.map((t=>t.plugin_url===e?{...t,installed:!0,active:!0}:t)),!0;throw t.message.includes("Plugin file does not exist")?new Error((0,a.__)("Plugin file does not exist","wp-graphql")):new Error((0,a.__)("Activation failed","wp-graphql"))}catch(e){throw w((0,a.__)("Activation failed","wp-graphql"),e.message||(0,a.__)("Activation failed","wp-graphql")),e}finally{s(!1),o(!1)}};return{installing:i,activating:r,status:p,error:u,installPlugin:async()=>{s(!0),w((0,a.__)("Installing...","wp-graphql"));let n=new URL(e).pathname.split("/").filter(Boolean).pop();try{if("inactive"!==(await l()({path:"/wp/v2/plugins",method:"POST",data:{slug:n,status:"inactive"},headers:{"X-WP-Nonce":wpgraphqlExtensions.nonce}})).status)throw new Error((0,a.__)("Installation failed","wp-graphql"));await h(t)}catch(e){if(!e.message.includes("destination folder already exists"))throw w((0,a.__)("Installation failed","wp-graphql"),e.message||(0,a.__)("Installation failed","wp-graphql")),s(!1),e;await h(t)}},activatePlugin:h}})(e.plugin_url,e.plugin_path),[w,h]=(0,t.useState)(e.installed),[g,_]=(0,t.useState)(e.active),[m,x]=(0,t.useState)(!0);(0,t.useEffect)((()=>{h(e.installed),_(e.active)}),[e]);const b=new URL(e.plugin_url).host,{buttonText:f,buttonDisabled:v}=((e,t,n,i,s,l,r)=>{let o,p=!1,c=null;const u=e=>()=>window.open(e,"_blank");if(s)o=(0,a.__)("Installing...","wp-graphql"),p=!0;else if(l)o=(0,a.__)("Activating...","wp-graphql"),p=!0;else if(i)o=(0,a.__)("Active","wp-graphql"),p=!0;else if(n)o=(0,a.__)("Activate","wp-graphql"),c=r;else{const e=new URL(t).hostname.toLowerCase();switch(!0){case/github\.com$/.test(e):o=(0,a.__)("View on GitHub","wp-graphql"),c=u(t);break;case/bitbucket\.org$/.test(e):o=(0,a.__)("View on Bitbucket","wp-graphql"),c=u(t);break;case/gitlab\.com$/.test(e):o=(0,a.__)("View on GitLab","wp-graphql"),c=u(t);break;case/wordpress\.org$/.test(e):o=(0,a.__)("Install & Activate","wp-graphql"),c=r;break;default:o=(0,a.__)("View Plugin","wp-graphql"),c=u(t)}}return{buttonText:o,buttonDisabled:p,buttonOnClick:c}})(0,e.plugin_url,w,g,s,o),q=({author:e})=>e&&e.name&&e.homepage?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("em",{children:"By "}),(0,r.jsx)("cite",{children:(0,r.jsx)("a",{href:e.homepage,target:"_blank",rel:"noopener noreferrer",children:e.name})},e.homepage)]}):null;return(0,r.jsxs)("div",{className:"plugin-card",children:[(0,r.jsxs)("div",{className:"plugin-card-top",children:[(0,r.jsxs)("div",{className:"name column-name",children:[(0,r.jsx)("h2",{children:e.name}),(0,r.jsx)(q,{author:e.author}),e.experiment&&(0,r.jsx)("em",{className:"plugin-experimental",children:"(experimental)"})]}),(0,r.jsx)("div",{className:"action-links",children:(0,r.jsxs)("ul",{className:"plugin-action-buttons",children:[b.includes("wordpress.org")&&(0,r.jsx)("li",{children:(0,r.jsxs)("button",{type:"button",className:"button "+(g?"button-disabled":"button-primary"),disabled:v,onClick:async()=>{const t=w,n=g;try{w?(await d(e.plugin_path),_(!0)):(await u(),h(!0),_(!0))}catch(e){h(t),_(n)}finally{window.wpgraphqlExtensions.extensions=window.wpgraphqlExtensions.extensions.map((t=>t.plugin_url===e.plugin_url?{...t,installed:w,active:g}:t))}},children:[f,(s||o)&&(0,r.jsx)(i.Spinner,{})]})}),b.includes("github.com")&&(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:e.plugin_url,target:"_blank",rel:"noopener noreferrer",className:"button button-secondary",children:(0,a.__)("View on GitHub","wp-graphql")})}),e.support_url&&(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:e.support_url,target:"_blank",rel:"noopener noreferrer",className:"thickbox open-plugin-details-modal",children:(0,a.__)("Get Support","wp-graphql")})}),e.settings_url&&(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:e.settings_url,children:(0,a.__)("Settings","wp-graphql")})})]})}),(0,r.jsx)("div",{className:"desc column-description",children:(0,r.jsx)("p",{children:e.description})})]}),c&&m&&(0,r.jsx)(i.Notice,{status:"error",isDismissible:!0,onRemove:()=>x(!1),children:c})]})},p=()=>{const[e,t]=(0,n.useState)([]);return(0,n.useEffect)((()=>{window.wpgraphqlExtensions&&window.wpgraphqlExtensions.extensions&&t(window.wpgraphqlExtensions.extensions)}),[]),(0,r.jsx)("div",{className:"wp-clearfix",children:(0,r.jsx)("div",{className:"plugin-cards",children:e.map((e=>(0,r.jsx)(o,{plugin:e},e.plugin_url)))})})};document.addEventListener("DOMContentLoaded",(()=>{const e=document.getElementById("wpgraphql-extensions");e&&(0,t.createRoot)(e).render((0,t.createElement)(p))}))})(); |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization High
github.com
Copilot Autofix AI 11 days ago
Copilot could not generate an autofix suggestion
Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR diff size of 8527 lines exceeds the maximum allowed for the inline comments feature.
Code Climate has analyzed commit 69e911a and detected 11 issues on this pull request. Here's the issue category breakdown:
View more on Code Climate. |
This is the 1st pass at #304
Features
This page is registered as a submenu of WPGraphQL:
/wp-admin/admin.php?page=wpgraphql-extensions
UI Scenarios
Demo
extensions.page.mov
Key Points
Possible Additions
TODO