updated plugin Jetpack Protect version 5.0.0
This commit is contained in:
@ -5,16 +5,131 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 4.0.0 - 2025-03-24
|
||||
## 5.0.0 - 2026-04-11
|
||||
### Security
|
||||
- WAF: Fix issue that potentially allowed bypassing WAF rules. [#47692]
|
||||
|
||||
### Added
|
||||
- Add `jetpack_account_protection_send_auth_email` filter to allow custom handling of the verification email. [#48003]
|
||||
- Add Jetpack Protect details page for users without the dedicated Jetpack Protect plugin. [#46630]
|
||||
- IDC: Add revalidation for IDCs. [#46268]
|
||||
|
||||
### Changed
|
||||
- Scanner: add threat count to tab [#40056]
|
||||
- Scanner: animated the "scan in progress" placeholder image [#39825]
|
||||
- General: indicate compatibility with the upcoming version of WordPress - 6.7. [#39786]
|
||||
- Dependencies: Update lock file to keep root requirements in sync. [#47418]
|
||||
- Migrate admin page header to use unified header pattern. [#47313]
|
||||
- My Jetpack: Check red bubble notification async when cache is not available. [#46396]
|
||||
- Remove translated product names from admin page headers and footers. [#47313]
|
||||
- Replace license activation link with a "Use license key" button in the header actions area. [#47434]
|
||||
- Switch to Native TypeScript compiler based on Go. [#47375]
|
||||
- Update composer.lock. [#46686]
|
||||
- Update dependencies. [#47472]
|
||||
- Update design of the sidebar upsell. [#47909]
|
||||
- Update package dependencies. [#46143] [#46430] [#46456] [#46512] [#46552] [#46647] [#46785] [#46854] [#47002] [#47021] [#47099] [#47173] [#47285] [#47300] [#47371] [#47496] [#47505] [#47684] [#47825] [#47890] [#47998]
|
||||
|
||||
### Removed
|
||||
- General: Update minimum WordPress version to 6.8. [#46801]
|
||||
|
||||
### Fixed
|
||||
- Admin Page: Restore border on header component. [#47425]
|
||||
- Constrain license activation link width on mobile to prevent header overflow. [#47431]
|
||||
- Ensure proper flags are used with `json_encode()`. [#46117]
|
||||
- Fix TypeScript errors detected by tsgo. [#47419] [#47409]
|
||||
|
||||
## 4.4.1 - 2025-11-21
|
||||
### Added
|
||||
- Tested up to WordPress 6.9. [#45571]
|
||||
|
||||
### Changed
|
||||
- Replace icons removed from @wordpress/icons with alternatives. [#45760]
|
||||
- Update dependencies. [#45488]
|
||||
- Update package dependencies. [#45478] [#45652] [#45676] [#45737] [#45756] [#45915] [#45932]
|
||||
|
||||
### Fixed
|
||||
- Jetpack: remove getIconColor functions for block icons [#45992]
|
||||
- My Jetpack: Fix expiring renewal prompt to show all products [#45995]
|
||||
- My Jetpack page: fix visual compatibility issue with Hello Dolly plugin. [#45474]
|
||||
|
||||
## 4.4.0 - 2025-10-10
|
||||
### Added
|
||||
- Add typecheck script. [#44787]
|
||||
- Add typecheck support for E2E tests. [#44788]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: Fix multisite availability check for restricted products and modules. [#44710]
|
||||
- My Jetpack: Unify the user connection flow with a unified screen. [#44469]
|
||||
- Remove CRM installation nudge for Complete plan users. [#45026]
|
||||
- Update package dependencies. [#44677] [#44701] [#44725] [#45027] [#45096] [#45097] [#45173] [#45200] [#45229] [#45298] [#45299] [#45334] [#45335]
|
||||
|
||||
### Fixed
|
||||
- I18n: Improve context hints in comments for translators. [#44686]
|
||||
- My Jetpack: Prevent expiration alerts for products covered by active bundles. [#44586]
|
||||
|
||||
## 4.3.0 - 2025-07-30
|
||||
### Added
|
||||
- Add UI confirmation via text box when deleting an extension via delete-fixer so that the user is fully aware that it may break their site. [#44521]
|
||||
- My Jetpack: Add analytics for empty product search results. [#44344]
|
||||
|
||||
### Changed
|
||||
- E2E tests: remove redundant logic in test fixture and converted the fixture to Typscript [#44327]
|
||||
- Improve performance of wpcom comments liking by caching and minimizing API requests. [#44205]
|
||||
- My Jetpack: Enabled access to My Jetpack on WP Multisite. [#44260]
|
||||
- Sync: Ignore the ActivityPub Outbox CPT. [#44222]
|
||||
- Update package dependencies. [#44206]
|
||||
|
||||
### Fixed
|
||||
- My Jetpack: Fix footer alignment for disconnected accounts. [#44468]
|
||||
- My Jetpack: Restore plan purchase link. [#44535]
|
||||
- Update JITMs to remove jQuery dependency. [#43783]
|
||||
|
||||
## 4.2.0 - 2025-07-03
|
||||
### Added
|
||||
- WAF: Add account recovery flow for blocklisted IP addresses. [#43051]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: Update Stats card to include a chart for better analytics. [#43870]
|
||||
- Update package dependencies. [#44151]
|
||||
|
||||
### Removed
|
||||
- Remove the need to add FTP/SSH credentials to run auto threat fixers. [#43935]
|
||||
|
||||
### Fixed
|
||||
- JITM: Fix ineffective caching due to expired plugin sync transient. [#44117]
|
||||
- My Jetpack: Use compact number notation in the Protect card. [#43977]
|
||||
- WAF: Fix PHP warnings for Brute_Force_Protection->get_local_host(). [#44170]
|
||||
|
||||
## 4.1.0 - 2025-06-05
|
||||
### Added
|
||||
- Scanner: Add functionality to correctly display database threats in the Protect UI. [#43663]
|
||||
- Account Protection: Add the Account Protection module toggle. [#40925]
|
||||
- My Jetpack: Add user tour. [#42880]
|
||||
- My Jetpack: Improve the onboarding experience of Jetpack guiding the users through a new onboarding process. [#42757]
|
||||
|
||||
### Changed
|
||||
- Connection: Allow pre-selected login providers. [#42662]
|
||||
- General: Indicate compatibility with WordPress 6.8. [#42701]
|
||||
- My Jetpack: Optimize the images for onboarding slider for faster page load. [#43473]
|
||||
- My Jetpack: Update the onboarding UI, changing it to a single button. [#43203]
|
||||
- General: Update package dependencies. [#43766]
|
||||
|
||||
### Removed
|
||||
- General: Update minimum WordPress version to 6.7. [#43192]
|
||||
|
||||
### Fixed
|
||||
- JS Packages: Decrease CSS priority of global styles to prevent them from applying within the editor. [#43035]
|
||||
- My Jetpack: Fix Onboarding UI responsiveness at 600px. [#43533]
|
||||
- My Jetpack: Fix readability of license activation button on hover. [#43550]
|
||||
- My Jetpack: Prevent social login from getting stuck when email input is not empty. [#43158]
|
||||
- Readme: Clarify language in the plugin readme regarding malware and vulnerability scanning. [#43775]
|
||||
|
||||
## 4.0.0 - 2025-03-24
|
||||
### Changed
|
||||
- Scanner: Add threat count to tab. [#40056]
|
||||
- Scanner: Animate the "scan in progress" placeholder image. [#39825]
|
||||
- General: Indicate compatibility with WordPress 6.7. [#39786]
|
||||
- General: Update package dependencies. [#42511]
|
||||
|
||||
### Removed
|
||||
- Firewall: removed "new" badge from tab. [#41902]
|
||||
- Firewall: Remove "new" badge from tab. [#41902]
|
||||
- General: Update minimum PHP version to 7.2. [#40147]
|
||||
- General: Update minimum WordPress version to 6.6. [#40146]
|
||||
|
||||
|
||||
@ -9,24 +9,23 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
<https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
@ -36,48 +35,48 @@ using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
@ -94,7 +93,7 @@ is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
@ -105,29 +104,29 @@ along with the Program.
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
@ -149,26 +148,26 @@ with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
@ -187,7 +186,7 @@ access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
@ -195,7 +194,7 @@ However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
@ -204,7 +203,7 @@ Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
@ -212,7 +211,7 @@ restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
@ -244,7 +243,7 @@ impose that choice.
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
@ -252,7 +251,7 @@ those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
@ -265,7 +264,7 @@ Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
@ -273,9 +272,9 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
@ -285,7 +284,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
@ -295,45 +294,44 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
@ -344,11 +342,11 @@ You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
|
||||
@ -1,21 +1,25 @@
|
||||
@font-face {
|
||||
font-family: 'jetpack-protect';
|
||||
src: url('fonts/jetpack-protect.eot?31wpn');
|
||||
src: url('fonts/jetpack-protect.eot?31wpn#iefix') format('embedded-opentype'),
|
||||
url('fonts/jetpack-protect.ttf?31wpn') format('truetype'),
|
||||
url('fonts/jetpack-protect.woff?31wpn') format('woff'),
|
||||
url('fonts/jetpack-protect.svg?31wpn#jetpack-protect') format('svg');
|
||||
font-weight: normal;
|
||||
font-family: jetpack-protect;
|
||||
src: url(fonts/jetpack-protect.eot?31wpn);
|
||||
src:
|
||||
url(fonts/jetpack-protect.eot?31wpn#iefix) format("embedded-opentype"),
|
||||
url(fonts/jetpack-protect.ttf?31wpn) format("truetype"),
|
||||
url(fonts/jetpack-protect.woff?31wpn) format("woff"),
|
||||
url(fonts/jetpack-protect.svg?31wpn#jetpack-protect) format("svg");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
}
|
||||
}
|
||||
|
||||
[class^="jp-protect-icon"], [class*=" jp-protect-icon"] {
|
||||
/* use !important to prevent issues with browser extensions that change fonts */
|
||||
font-family: 'jetpack-protect' !important;
|
||||
[class^="jp-protect-icon"],
|
||||
[class*=" jp-protect-icon"] {
|
||||
|
||||
/* Use !important to avoid issues with browser extensions that change fonts. */
|
||||
/* stylelint-disable-next-line font-family-no-missing-generic-family-keyword -- this is a one-off icon font. */
|
||||
font-family: jetpack-protect !important;
|
||||
speak: never;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-weight: 400;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
@ -25,6 +29,6 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.jp-protect-icon:before {
|
||||
.jp-protect-icon::before {
|
||||
content: "\e900";
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
<svg width="380" height="183" viewBox="0 0 380 183" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.75" filter="url(#filter0_f_5953_11924)">
|
||||
<path d="M360 -60C360 7.93102 304.931 63 237 63C169.069 63 114 7.93102 114 -60C114 -127.931 169.069 -183 237 -183C304.931 -183 360 -127.931 360 -60Z" fill="url(#paint0_linear_5953_11924)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_f_5953_11924" x="-6" y="-303" width="486" height="486" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="60" result="effect1_foregroundBlur_5953_11924"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_5953_11924" x1="360" y1="-60" x2="114" y2="-60" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#48FF50"/>
|
||||
<stop offset="0.471846" stop-color="#108642"/>
|
||||
<stop offset="1" stop-color="#2E38FA"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 990 B |
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('jetpack-connection', 'jetpack-script-data', 'moment', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '5a27a9f58fb4802d8a58');
|
||||
<?php return array('dependencies' => array('jetpack-connection', 'jetpack-script-data', 'moment', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '3146a6f91e54a1fdb28d');
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,35 +1,5 @@
|
||||
/*
|
||||
* Exposes number format capability
|
||||
*
|
||||
* @copyright Copyright (c) 2013 Kevin van Zonneveld (http://kvz.io) and Contributors (http://phpjs.org/authors).
|
||||
* @license See CREDITS.md
|
||||
* @see https://github.com/kvz/phpjs/blob/ffe1356af23a6f2512c84c954dd4e828e92579fa/functions/strings/number_format.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* @remix-run/router v1.21.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router DOM v6.28.1
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router v6.28.1
|
||||
* react-router v7.12.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -5,24 +5,25 @@
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"automattic/jetpack-assets": "^4.0.14",
|
||||
"automattic/jetpack-admin-ui": "^0.5.7",
|
||||
"automattic/jetpack-autoloader": "^5.0.5",
|
||||
"automattic/jetpack-composer-plugin": "^4.0.4",
|
||||
"automattic/jetpack-config": "^3.0.1",
|
||||
"automattic/jetpack-my-jetpack": "^5.9.1",
|
||||
"automattic/jetpack-plugins-installer": "^0.5.4",
|
||||
"automattic/jetpack-sync": "^4.9.2",
|
||||
"automattic/jetpack-transport-helper": "^0.3.1",
|
||||
"automattic/jetpack-plans": "^0.6.1",
|
||||
"automattic/jetpack-waf": "^0.23.8",
|
||||
"automattic/jetpack-status": "^5.0.10",
|
||||
"automattic/jetpack-protect-status": "^0.5.8"
|
||||
"automattic/jetpack-assets": "^4.3.32",
|
||||
"automattic/jetpack-admin-ui": "^0.8.0",
|
||||
"automattic/jetpack-autoloader": "^5.0.16",
|
||||
"automattic/jetpack-composer-plugin": "^4.0.5",
|
||||
"automattic/jetpack-config": "^3.1.1",
|
||||
"automattic/jetpack-my-jetpack": "^5.34.2",
|
||||
"automattic/jetpack-plugins-installer": "^0.5.7",
|
||||
"automattic/jetpack-sync": "^4.35.0",
|
||||
"automattic/jetpack-transport-helper": "^0.3.5",
|
||||
"automattic/jetpack-plans": "^0.11.3",
|
||||
"automattic/jetpack-waf": "^0.28.2",
|
||||
"automattic/jetpack-status": "^6.1.2",
|
||||
"automattic/jetpack-protect-status": "^0.7.8",
|
||||
"automattic/jetpack-account-protection": "^0.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "^3.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.2",
|
||||
"automattic/phpunit-select-config": "^1.0.1"
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.14",
|
||||
"automattic/phpunit-select-config": "^1.0.4"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
@ -72,6 +73,6 @@
|
||||
"automattic/jetpack-autoloader": true,
|
||||
"automattic/jetpack-composer-plugin": true
|
||||
},
|
||||
"autoloader-suffix": "c4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ4_0_0"
|
||||
"autoloader-suffix": "c4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ5_0_0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* Plugin Name: Jetpack Protect
|
||||
* Plugin URI: https://wordpress.org/plugins/jetpack-protect
|
||||
* Description: Security tools that keep your site safe and sound, from posts to plugins.
|
||||
* Version: 4.0.0
|
||||
* Version: 5.0.0
|
||||
* Author: Automattic - Jetpack Security team
|
||||
* Author URI: https://jetpack.com/protect/
|
||||
* License: GPLv2 or later
|
||||
@ -24,15 +24,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
define( 'JETPACK_PROTECT_VERSION', '4.0.0' );
|
||||
define( 'JETPACK_PROTECT_VERSION', '5.0.0' );
|
||||
define( 'JETPACK_PROTECT_DIR', plugin_dir_path( __FILE__ ) );
|
||||
define( 'JETPACK_PROTECT_ROOT_FILE', __FILE__ );
|
||||
define( 'JETPACK_PROTECT_ROOT_FILE_RELATIVE_PATH', plugin_basename( __FILE__ ) );
|
||||
|
||||
@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [3.0.5] - 2025-04-28
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [3.0.4] - 2025-03-21
|
||||
### Changed
|
||||
- Internal updates.
|
||||
@ -167,6 +171,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Creates the MC Stats package
|
||||
|
||||
[3.0.5]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v3.0.4...v3.0.5
|
||||
[3.0.4]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v3.0.3...v3.0.4
|
||||
[3.0.3]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v3.0.2...v3.0.3
|
||||
[3.0.2]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v3.0.1...v3.0.2
|
||||
|
||||
@ -7,9 +7,9 @@
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "^3.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.2",
|
||||
"automattic/phpunit-select-config": "^1.0.1"
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.5",
|
||||
"automattic/phpunit-select-config": "^1.0.3"
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.3.0] - 2026-04-11
|
||||
### Added
|
||||
- Add `jetpack_account_protection_send_auth_email` filter to allow custom handling of the verification email. [#48003]
|
||||
|
||||
## [0.2.12] - 2026-02-23
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [0.2.11] - 2026-02-02
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [0.2.10] - 2025-12-15
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.2.9] - 2025-12-08
|
||||
### Fixed
|
||||
- Ensure proper flags are used with `json_encode()`. [#46092]
|
||||
|
||||
## [0.2.8] - 2025-11-10
|
||||
### Changed
|
||||
- Tests: Ensure PHP 8.5 compatibility. [#45769]
|
||||
|
||||
## [0.2.7] - 2025-08-04
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.2.6] - 2025-07-28
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.2.5] - 2025-07-21
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.2.4] - 2025-05-05
|
||||
### Fixed
|
||||
- Linting: Do additional stylesheet cleanup. [#43247]
|
||||
- Prevent PHP error from errant third-party hook params. [#43352]
|
||||
|
||||
## [0.2.3] - 2025-04-28
|
||||
### Fixed
|
||||
- Fix an issue where authentication could fail when other authentication plugins are active. [#43240]
|
||||
- Linting: Fix more Stylelint violations. [#43213]
|
||||
|
||||
## [0.2.2] - 2025-04-14
|
||||
### Fixed
|
||||
- Linting: Update stylesheets to use WordPress rules for fonts and colors. [#42920] [#42928]
|
||||
- Fix: Improve compatibility with code using stdClass objects in `profile_update` hook. [#43045]
|
||||
|
||||
## [0.2.1] - 2025-04-07
|
||||
### Changed
|
||||
- Linting: First pass of style coding standards. [#42734]
|
||||
|
||||
## [0.2.0] - 2025-04-01
|
||||
### Changed
|
||||
- Add a default value for the error param in the `wp_login_failed` action callback. [#42819]
|
||||
- Fix potential `wp_login_failed` action conflicts. [#42825]
|
||||
|
||||
## 0.1.0 - 2025-03-31
|
||||
### Added
|
||||
- Add initial account protection features. [#40925]
|
||||
- Add a user requires protection filter. [#40925]
|
||||
- Initial version. [#40923]
|
||||
- Use jetpack-config package for Account Protection initialization. [#40925]
|
||||
- Use jetpack-logo package for Account Protection logos. [#40925]
|
||||
|
||||
[0.3.0]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.12...v0.3.0
|
||||
[0.2.12]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.11...v0.2.12
|
||||
[0.2.11]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.10...v0.2.11
|
||||
[0.2.10]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.9...v0.2.10
|
||||
[0.2.9]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.8...v0.2.9
|
||||
[0.2.8]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.7...v0.2.8
|
||||
[0.2.7]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.6...v0.2.7
|
||||
[0.2.6]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.5...v0.2.6
|
||||
[0.2.5]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.4...v0.2.5
|
||||
[0.2.4]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.3...v0.2.4
|
||||
[0.2.3]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.2...v0.2.3
|
||||
[0.2.2]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.1...v0.2.2
|
||||
[0.2.1]: https://github.com/Automattic/jetpack-account-protection/compare/v0.2.0...v0.2.1
|
||||
[0.2.0]: https://github.com/Automattic/jetpack-account-protection/compare/v0.1.0...v0.2.0
|
||||
@ -0,0 +1,355 @@
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
<https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@ -0,0 +1,47 @@
|
||||
# Security Policy
|
||||
|
||||
Full details of the Automattic Security Policy can be found on [automattic.com](https://automattic.com/security/).
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Generally, only the latest version of Jetpack and its associated plugins have continued support. If a critical vulnerability is found in the current version of a plugin, we may opt to backport any patches to previous versions.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Our HackerOne program covers the below plugin software, as well as a variety of related projects and infrastructure:
|
||||
|
||||
* [Jetpack](https://jetpack.com/)
|
||||
* Jetpack Backup
|
||||
* Jetpack Boost
|
||||
* Jetpack CRM
|
||||
* Jetpack Protect
|
||||
* Jetpack Search
|
||||
* Jetpack Social
|
||||
* Jetpack VideoPress
|
||||
|
||||
**For responsible disclosure of security issues and to be eligible for our bug bounty program, please submit your report via the [HackerOne](https://hackerone.com/automattic) portal.**
|
||||
|
||||
Our most critical targets are:
|
||||
|
||||
* Jetpack and the Jetpack composer packages (all within this repo)
|
||||
* Jetpack.com -- the primary marketing site.
|
||||
* cloud.jetpack.com -- a management site.
|
||||
* wordpress.com -- the shared management site for both Jetpack and WordPress.com sites.
|
||||
|
||||
For more targets, see the `In Scope` section on [HackerOne](https://hackerone.com/automattic).
|
||||
|
||||
_Please note that the **WordPress software is a separate entity** from Automattic. Please report vulnerabilities for WordPress through [the WordPress Foundation's HackerOne page](https://hackerone.com/wordpress)._
|
||||
|
||||
## Guidelines
|
||||
|
||||
We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines:
|
||||
|
||||
* Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
|
||||
* Pen-testing Production:
|
||||
* Please **setup a local environment** instead whenever possible. Most of our code is open source (see above).
|
||||
* If that's not possible, **limit any data access/modification** to the bare minimum necessary to reproduce a PoC.
|
||||
* **_Don't_ automate form submissions!** That's very annoying for us, because it adds extra work for the volunteers who manage those systems, and reduces the signal/noise ratio in our communication channels.
|
||||
* To be eligible for a bounty, all of these guidelines must be followed.
|
||||
* Be Patient - Give us a reasonable time to correct the issue before you disclose the vulnerability.
|
||||
|
||||
We also expect you to comply with all applicable laws. You're responsible to pay any taxes associated with your bounties.
|
||||
@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "automattic/jetpack-account-protection",
|
||||
"description": "Account protection",
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"automattic/jetpack-connection": "^8.2.2",
|
||||
"automattic/jetpack-logo": "^3.0.5",
|
||||
"automattic/jetpack-constants": "^3.0.8",
|
||||
"automattic/jetpack-status": "^6.1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.14",
|
||||
"automattic/jetpack-test-environment": "@dev",
|
||||
"automattic/phpunit-select-config": "^1.0.4"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"build-development": "echo 'Add your build step to composer.json, please!'",
|
||||
"build-production": "echo 'Add your build step to composer.json, please!'",
|
||||
"phpunit": [
|
||||
"phpunit-select-config phpunit.#.xml.dist --colors=always"
|
||||
],
|
||||
"test-coverage": [
|
||||
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
|
||||
],
|
||||
"test-php": [
|
||||
"@composer phpunit"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"extra": {
|
||||
"autotagger": true,
|
||||
"branch-alias": {
|
||||
"dev-trunk": "0.3.x-dev"
|
||||
},
|
||||
"changelogger": {
|
||||
"link-template": "https://github.com/Automattic/jetpack-account-protection/compare/v${old}...v${new}"
|
||||
},
|
||||
"mirror-repo": "Automattic/jetpack-account-protection",
|
||||
"textdomain": "jetpack-account-protection",
|
||||
"version-constants": {
|
||||
"::PACKAGE_VERSION": "src/class-account-protection.php"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,282 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used to define Account Protection.
|
||||
*
|
||||
* @package automattic/jetpack-account-protection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Account_Protection;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\Jetpack\Modules;
|
||||
use Automattic\Jetpack\Status\Host;
|
||||
|
||||
/**
|
||||
* Class Account_Protection
|
||||
*/
|
||||
class Account_Protection {
|
||||
const PACKAGE_VERSION = '0.3.0';
|
||||
const ACCOUNT_PROTECTION_MODULE_NAME = 'account-protection';
|
||||
|
||||
/**
|
||||
* Account_Protection instance
|
||||
*
|
||||
* @var Account_Protection
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Flag to track if hooks have been registered.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $hooks_registered = false;
|
||||
|
||||
/**
|
||||
* Modules instance.
|
||||
*
|
||||
* @var Modules
|
||||
*/
|
||||
private $modules;
|
||||
|
||||
/**
|
||||
* Password detection instance.
|
||||
*
|
||||
* @var Password_Detection
|
||||
*/
|
||||
private $password_detection;
|
||||
|
||||
/**
|
||||
* Password manager instance
|
||||
*
|
||||
* @var Password_Manager
|
||||
*/
|
||||
private $password_manager;
|
||||
|
||||
/**
|
||||
* Password strength meter instance
|
||||
*
|
||||
* @var Password_Strength_Meter
|
||||
*/
|
||||
private $password_strength_meter;
|
||||
|
||||
/**
|
||||
* Initialize the Account_Protection instance
|
||||
*
|
||||
* @return Account_Protection
|
||||
*/
|
||||
public static function instance(): Account_Protection {
|
||||
if ( self::$instance === null ) {
|
||||
self::$instance = new Account_Protection();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the configurations needed for the account protection module.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(): void {
|
||||
if ( self::$hooks_registered ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->register_hooks();
|
||||
|
||||
if ( $this->is_enabled() ) {
|
||||
$this->register_runtime_hooks();
|
||||
}
|
||||
|
||||
self::$hooks_registered = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Account_Protection constructor.
|
||||
*
|
||||
* @param ?Modules $modules Modules instance.
|
||||
* @param ?Password_Detection $password_detection Password detection instance.
|
||||
* @param ?Password_Manager $password_manager Password manager instance.
|
||||
* @param ?Password_Strength_Meter $password_strength_meter Password strength meter instance.
|
||||
*/
|
||||
public function __construct( ?Modules $modules = null, ?Password_Detection $password_detection = null, ?Password_Manager $password_manager = null, ?Password_Strength_Meter $password_strength_meter = null ) {
|
||||
$this->modules = $modules ?? new Modules();
|
||||
$this->password_detection = $password_detection ?? new Password_Detection();
|
||||
$this->password_manager = $password_manager ?? new Password_Manager();
|
||||
$this->password_strength_meter = $password_strength_meter ?? new Password_Strength_Meter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks for module activation and environment validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function register_hooks(): void {
|
||||
// Do not run in unsupported environments
|
||||
add_filter( 'jetpack_get_available_modules', array( $this, 'remove_module_on_unsupported_environments' ) );
|
||||
add_filter( 'jetpack_get_available_standalone_modules', array( $this, 'remove_standalone_module_on_unsupported_environments' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks for runtime operations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function register_runtime_hooks(): void {
|
||||
$this->register_password_detection_hooks();
|
||||
$this->register_strong_passwords_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks for password detection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_password_detection_hooks(): void {
|
||||
add_action( 'wp_authenticate_user', array( $this->password_detection, 'login_form_password_detection' ), 10, 2 );
|
||||
add_action( 'login_form_password-detection', array( $this->password_detection, 'render_page' ), 10, 2 );
|
||||
add_action( 'wp_enqueue_scripts', array( $this->password_detection, 'enqueue_styles' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks for password manager.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_password_manager_hooks(): void {
|
||||
add_action( 'user_profile_update_errors', array( $this->password_manager, 'validate_profile_update' ), 10, 3 );
|
||||
add_action( 'validate_password_reset', array( $this->password_manager, 'validate_password_reset' ), 10, 2 );
|
||||
add_action( 'profile_update', array( $this->password_manager, 'on_profile_update' ), 10, 2 );
|
||||
add_action( 'after_password_reset', array( $this->password_manager, 'on_password_reset' ), 10, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks for password strength meter.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_password_strength_meter_hooks(): void {
|
||||
add_action( 'admin_enqueue_scripts', array( $this->password_strength_meter, 'enqueue_jetpack_password_strength_meter_profile_script' ) );
|
||||
add_action( 'login_enqueue_scripts', array( $this->password_strength_meter, 'enqueue_jetpack_password_strength_meter_reset_script' ) );
|
||||
add_action( 'wp_ajax_validate_password_ajax', array( $this->password_strength_meter, 'validate_password_ajax' ) );
|
||||
add_action( 'wp_ajax_nopriv_validate_password_ajax', array( $this->password_strength_meter, 'validate_password_ajax' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks for strong passwords.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_strong_passwords_hooks(): void {
|
||||
$this->register_password_manager_hooks();
|
||||
$this->register_password_strength_meter_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the account protection module is enabled on the site.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_enabled(): bool {
|
||||
return $this->modules->is_active( self::ACCOUNT_PROTECTION_MODULE_NAME );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the account protection module.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function enable(): bool {
|
||||
// Return true if already enabled.
|
||||
if ( $this->is_enabled() ) {
|
||||
return true;
|
||||
}
|
||||
return $this->modules->activate( self::ACCOUNT_PROTECTION_MODULE_NAME, false, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the account protection module.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function disable(): bool {
|
||||
// Return true if already disabled.
|
||||
if ( ! $this->is_enabled() ) {
|
||||
return true;
|
||||
}
|
||||
return $this->modules->deactivate( self::ACCOUNT_PROTECTION_MODULE_NAME );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if Account Protection is supported in the current environment.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_supported_environment(): bool {
|
||||
// Do not run when killswitch is enabled
|
||||
if ( defined( 'DISABLE_JETPACK_ACCOUNT_PROTECTION' ) && DISABLE_JETPACK_ACCOUNT_PROTECTION ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not run for WordPress.com Simple sites
|
||||
if ( ( new Host() )->is_wpcom_simple() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current Jetpack version is supported.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_unsupported_jetpack_version(): bool {
|
||||
// Do not run when Jetpack version is less than 14.5
|
||||
$jetpack_version = Constants::get_constant( 'JETPACK__VERSION' );
|
||||
if ( $jetpack_version && version_compare( $jetpack_version, '14.5', '<' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the Account Protection module when on an unsupported platform in Jetpack.
|
||||
*
|
||||
* @param array $modules Filterable value for `jetpack_get_available_modules`.
|
||||
*
|
||||
* @return array Array of module slugs.
|
||||
*/
|
||||
public function remove_module_on_unsupported_environments( array $modules ): array {
|
||||
if ( ! $this->is_supported_environment() ) {
|
||||
// Account protection should never be available on unsupported platforms.
|
||||
unset( $modules[ self::ACCOUNT_PROTECTION_MODULE_NAME ] );
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the Account Protection module when on an unsupported platform in a standalone plugin.
|
||||
*
|
||||
* @param array $modules Filterable value for `jetpack_get_available_standalone_modules`.
|
||||
*
|
||||
* @return array Array of module slugs.
|
||||
*/
|
||||
public function remove_standalone_module_on_unsupported_environments( array $modules ): array {
|
||||
if ( ! $this->is_supported_environment() ) {
|
||||
// Account Protection should never be available on unsupported platforms.
|
||||
$modules = array_filter(
|
||||
$modules,
|
||||
function ( $module ) {
|
||||
return $module !== self::ACCOUNT_PROTECTION_MODULE_NAME;
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used to define Config.
|
||||
*
|
||||
* @package automattic/jetpack-account-protection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Account_Protection;
|
||||
|
||||
/**
|
||||
* Class Config
|
||||
*/
|
||||
class Config {
|
||||
public const PREFIX = 'jetpack_account_protection';
|
||||
public const SUPPORT_LINK = 'https://jetpack.com/?post_type=jetpack_support&p=324199';
|
||||
public const RECENT_PASSWORD_HASHES_USER_META_KEY = self::PREFIX . '_recent_password_hashes';
|
||||
|
||||
// Password Detection Constants
|
||||
public const PASSWORD_DETECTION_EMAIL_SENT_EXPIRATION = 600; // 10 minutes
|
||||
public const PASSWORD_DETECTION_EMAIL_REQUEST_LIMIT = 4;
|
||||
|
||||
// Password Manager Constants
|
||||
public const PASSWORD_MANAGER_RECENT_PASSWORDS_LIMIT = 10;
|
||||
|
||||
// Validation Service Constants
|
||||
public const VALIDATION_SERVICE_MIN_LENGTH = 6;
|
||||
public const VALIDATION_SERVICE_MAX_LENGTH = 150;
|
||||
}
|
||||
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used to define Email Service.
|
||||
*
|
||||
* @package automattic/jetpack-account-protection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Account_Protection;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Jetpack_Options;
|
||||
|
||||
/**
|
||||
* Class Email_Service
|
||||
*/
|
||||
class Email_Service {
|
||||
/**
|
||||
* Connection manager dependency.
|
||||
*
|
||||
* @var Connection_Manager
|
||||
*/
|
||||
private $connection_manager;
|
||||
|
||||
/**
|
||||
* Constructor for dependency injection.
|
||||
*
|
||||
* @param Connection_Manager|null $connection_manager Connection manager dependency.
|
||||
*/
|
||||
public function __construct(
|
||||
?Connection_Manager $connection_manager = null
|
||||
) {
|
||||
$this->connection_manager = $connection_manager ?? new Connection_Manager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the email using the API.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $auth_code The authentication code.
|
||||
*
|
||||
* @return true|\WP_Error True if the email was sent successfully, \WP_Error otherwise.
|
||||
*/
|
||||
public function api_send_auth_email( int $user_id, string $auth_code ) {
|
||||
$blog_id = Jetpack_Options::get_option( 'id' );
|
||||
|
||||
/**
|
||||
* Filters whether the Account Protection verification email should be handled externally.
|
||||
*
|
||||
* When the filter returns a truthy value, the default WPCOM API email send is skipped,
|
||||
* allowing sites to deliver the email locally (e.g. via `wp_mail()`).
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param bool $handled Whether the email has been handled. Default false.
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $auth_code The authentication code.
|
||||
* @param int $blog_id The blog ID, or false if not available.
|
||||
*/
|
||||
$handled = apply_filters( 'jetpack_account_protection_send_auth_email', false, $user_id, $auth_code, $blog_id );
|
||||
|
||||
if ( $handled ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! $blog_id || ! $this->connection_manager->is_connected() ) {
|
||||
return new \WP_Error( 'jetpack_connection_error', __( 'Jetpack is not connected. Please connect and try again.', 'jetpack-account-protection' ) );
|
||||
}
|
||||
|
||||
$body = array(
|
||||
'user_id' => $user_id,
|
||||
'code' => $auth_code,
|
||||
);
|
||||
|
||||
$response = $this->send_email_request( (int) $blog_id, $body );
|
||||
if ( is_wp_error( $response ) || empty( $response['body'] ) ) {
|
||||
return new \WP_Error( 'email_send_error', __( 'Failed to send authentication code. Please try again.', 'jetpack-account-protection' ) );
|
||||
}
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
if ( 200 !== $response_code ) {
|
||||
return new \WP_Error( $body['code'] ?? 'email_send_error', $body['message'] ?? __( 'Failed to send authentication code. Please try again.', 'jetpack-account-protection' ) );
|
||||
}
|
||||
|
||||
if ( empty( $body['email_send_success'] ) ) {
|
||||
return new \WP_Error( 'email_send_error', __( 'Failed to send authentication code. Please try again.', 'jetpack-account-protection' ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dependency decoupling for the static call to the client.
|
||||
*
|
||||
* @param int $blog_id Blog ID.
|
||||
* @param array $body The request body.
|
||||
* @return array|\WP_Error Response data or error.
|
||||
*/
|
||||
protected function send_email_request( int $blog_id, array $body ) {
|
||||
return Client::wpcom_json_api_request_as_blog(
|
||||
sprintf( '/sites/%d/jetpack-protect-send-verification-code', $blog_id ),
|
||||
'2',
|
||||
array(
|
||||
'method' => 'POST',
|
||||
),
|
||||
$body,
|
||||
'wpcom'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resend email attempts.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param array $transient_data The transient data.
|
||||
* @param string $token The token.
|
||||
*
|
||||
* @return true|\WP_Error True if the email was resent successfully, \WP_Error otherwise.
|
||||
*/
|
||||
public function resend_auth_email( int $user_id, array $transient_data, string $token ) {
|
||||
if ( $transient_data['requests'] >= Config::PASSWORD_DETECTION_EMAIL_REQUEST_LIMIT ) {
|
||||
return new \WP_Error( 'email_request_limit_exceeded', __( 'Email request limit exceeded. Please try again later.', 'jetpack-account-protection' ) );
|
||||
}
|
||||
|
||||
$auth_code = $this->generate_auth_code();
|
||||
$transient_data['auth_code'] = $auth_code;
|
||||
|
||||
$resend = $this->api_send_auth_email( $user_id, $auth_code );
|
||||
if ( is_wp_error( $resend ) ) {
|
||||
return $resend;
|
||||
}
|
||||
|
||||
++$transient_data['requests'];
|
||||
|
||||
if ( ! set_transient( Config::PREFIX . "_{$token}", $transient_data, Config::PASSWORD_DETECTION_EMAIL_SENT_EXPIRATION ) ) {
|
||||
return new \WP_Error( 'transient_set_error', __( 'Failed to set transient data. Please try again.', 'jetpack-account-protection' ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an auth code.
|
||||
*
|
||||
* @return string The generated auth code.
|
||||
*/
|
||||
public function generate_auth_code(): string {
|
||||
return (string) wp_rand( 100000, 999999 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Mask an email address like d*****@g*****.com.
|
||||
*
|
||||
* @param string $email The email address to mask.
|
||||
*
|
||||
* @return string The masked email address.
|
||||
*/
|
||||
public function mask_email_address( string $email ): string {
|
||||
$parts = explode( '@', $email );
|
||||
$name = substr( $parts[0], 0, 1 ) . str_repeat( '*', strlen( $parts[0] ) - 1 );
|
||||
$domain_parts = explode( '.', $parts[1] );
|
||||
$domain = substr( $domain_parts[0], 0, 1 ) . str_repeat( '*', strlen( $domain_parts[0] ) - 1 );
|
||||
|
||||
// Join all domain parts except the first one with dots
|
||||
$tld = implode( '.', array_slice( $domain_parts, 1 ) );
|
||||
|
||||
return "{$name}@{$domain}.{$tld}";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,547 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used to define Password Detection.
|
||||
*
|
||||
* @package automattic/jetpack-account-protection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Account_Protection;
|
||||
|
||||
use Automattic\Jetpack\Assets\Logo as Jetpack_Logo;
|
||||
|
||||
/**
|
||||
* Class Password_Detection
|
||||
*/
|
||||
class Password_Detection {
|
||||
/**
|
||||
* Email service dependency.
|
||||
*
|
||||
* @var Email_Service
|
||||
*/
|
||||
private $email_service;
|
||||
|
||||
/**
|
||||
* Validation service dependency.
|
||||
*
|
||||
* @var Validation_Service
|
||||
*/
|
||||
private $validation_service;
|
||||
|
||||
/**
|
||||
* Password_Detection constructor.
|
||||
*
|
||||
* @param ?Email_Service $email_service Email service instance.
|
||||
* @param ?Validation_Service $validation_service Validation service instance.
|
||||
*/
|
||||
public function __construct( ?Email_Service $email_service = null, ?Validation_Service $validation_service = null ) {
|
||||
$this->email_service = $email_service ?? new Email_Service();
|
||||
$this->validation_service = $validation_service ?? new Validation_Service();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password is safe after login.
|
||||
*
|
||||
* @param \WP_User|\WP_Error|null $user The user or error object, or null.
|
||||
* @param string|null $password The password.
|
||||
*
|
||||
* @return \WP_User|\WP_Error|null The user object, error object, or null.
|
||||
*/
|
||||
public function login_form_password_detection( $user, ?string $password ) {
|
||||
// First check if the user object and password are valid. Third-party plugins might pass
|
||||
// incompatible types to authentication hooks, so we need this extra check.
|
||||
if ( is_wp_error( $user ) || ! ( $user instanceof \WP_User ) || $password === null ) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
if ( ! $this->user_requires_protection( $user, $password ) ) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
// Skip if we're validating a Brute force protection recovery token
|
||||
if ( get_transient( 'jetpack_protect_recovery_key_validated_' . $user->ID ) ) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
if ( ! $this->validation_service->is_leaked_password( $password ) ) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
$auth_code = $this->email_service->generate_auth_code();
|
||||
$existing_transient_token = get_transient( Config::PREFIX . "_last_valid_token_{$user->ID}" );
|
||||
$existing_transient = $existing_transient_token ? get_transient( Config::PREFIX . "_{$existing_transient_token}" ) : null;
|
||||
|
||||
if ( $existing_transient && isset( $existing_transient['requests'] ) &&
|
||||
$existing_transient['requests'] >= Config::PASSWORD_DETECTION_EMAIL_REQUEST_LIMIT ) {
|
||||
|
||||
// Resend limit reached, prevent sending new email
|
||||
$this->set_transient_error(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => 'email_request_limit_exceeded',
|
||||
'message' => __( 'Email request limit exceeded. Please try again later.', 'jetpack-account-protection' ),
|
||||
)
|
||||
);
|
||||
|
||||
$this->redirect_and_exit( $this->get_redirect_url( $existing_transient_token ) );
|
||||
|
||||
}
|
||||
|
||||
$email_sent = $this->email_service->api_send_auth_email( $user->ID, $auth_code );
|
||||
|
||||
if ( is_wp_error( $email_sent ) ) {
|
||||
$this->set_transient_error(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => $email_sent->get_error_code(),
|
||||
'message' => $email_sent->get_error_message(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$new_transient_token = null;
|
||||
|
||||
// Update or create a transient token
|
||||
if ( $existing_transient ) {
|
||||
if ( ! is_wp_error( $email_sent ) ) {
|
||||
$existing_transient['auth_code'] = $auth_code;
|
||||
$existing_transient['requests'] = ( $existing_transient['requests'] ?? 0 ) + 1;
|
||||
|
||||
if ( ! set_transient( Config::PREFIX . "_{$existing_transient_token}", $existing_transient, Config::PASSWORD_DETECTION_EMAIL_SENT_EXPIRATION ) ) {
|
||||
$this->set_transient_error(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => 'transient_error',
|
||||
'message' => __( 'Failed to update authentication token. Please try again.', 'jetpack-account-protection' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$new_transient_token = $this->generate_and_store_transient_data( $user->ID, $auth_code );
|
||||
}
|
||||
|
||||
$this->redirect_and_exit( $this->get_redirect_url( $new_transient_token ? $new_transient_token : $existing_transient_token ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect and exit.
|
||||
*
|
||||
* @param string $redirect_location The redirect location.
|
||||
*
|
||||
* @return never
|
||||
*/
|
||||
protected function redirect_and_exit( string $redirect_location ) {
|
||||
wp_safe_redirect( $redirect_location );
|
||||
$this->exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit decoupling.
|
||||
*
|
||||
* @return never
|
||||
*/
|
||||
protected function exit() {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user by ID. Dependency decoupling.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return \WP_User|null The user object.
|
||||
*/
|
||||
protected function load_user( int $user_id ) {
|
||||
return get_user_by( 'ID', $user_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render password detection page.
|
||||
*/
|
||||
public function render_page() {
|
||||
if ( is_user_logged_in() ) {
|
||||
$this->redirect_and_exit( admin_url() );
|
||||
// @phan-suppress-next-line PhanPluginUnreachableCode This would fall through in unit tests otherwise.
|
||||
return;
|
||||
}
|
||||
|
||||
$token = isset( $_GET['token'] ) ? sanitize_text_field( wp_unslash( $_GET['token'] ) ) : null;
|
||||
$transient_data = get_transient( Config::PREFIX . "_{$token}" );
|
||||
if ( ! $transient_data ) {
|
||||
$this->redirect_to_login();
|
||||
// @phan-suppress-next-line PhanPluginUnreachableCode This would fall through in unit tests otherwise.
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = $transient_data['user_id'] ?? null;
|
||||
$user = $user_id ? $this->load_user( (int) $user_id ) : null;
|
||||
if ( ! $user instanceof \WP_User ) {
|
||||
$this->redirect_to_login();
|
||||
// @phan-suppress-next-line PhanPluginUnreachableCode This would fall through in unit tests otherwise.
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle resend email request
|
||||
if ( isset( $_GET['resend_email'] ) && $_GET['resend_email'] === '1' ) {
|
||||
if ( isset( $_GET['_wpnonce'] )
|
||||
&& wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'resend_email_nonce' )
|
||||
) {
|
||||
$email_resent = $this->email_service->resend_auth_email( $user->ID, $transient_data, $token );
|
||||
if ( is_wp_error( $email_resent ) ) {
|
||||
$this->set_transient_error(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => $email_resent->get_error_code(),
|
||||
'message' => $email_resent->get_error_message(),
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$this->set_transient_success(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => 'email_resend_success',
|
||||
'message' => __( 'Authentication email resent successfully.', 'jetpack-account-protection' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->redirect_and_exit( $this->get_redirect_url( $token ) );
|
||||
// @phan-suppress-next-line PhanPluginUnreachableCode This would fall through in unit tests otherwise.
|
||||
return;
|
||||
} else {
|
||||
$this->set_transient_error(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => 'email_resend_nonce_error',
|
||||
'message' => __( 'Resend nonce verification failed. Please try again.', 'jetpack-account-protection' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle verify form submission
|
||||
if ( isset( $_POST['verify'] ) ) {
|
||||
if ( ! empty( $_POST['_wpnonce_verify'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce_verify'] ) ), 'verify_action' ) ) {
|
||||
$user_input = isset( $_POST['user_input'] ) ? sanitize_text_field( wp_unslash( $_POST['user_input'] ) ) : null;
|
||||
|
||||
$this->handle_auth_form_submission( $user, $token, $transient_data['auth_code'] ?? null, $user_input );
|
||||
} else {
|
||||
$this->set_transient_error(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => 'verify_nonce_error',
|
||||
'message' => __( 'Verify nonce verification failed. Please try again.', 'jetpack-account-protection' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->render_content( $user, $token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract transient data safely and delete the transient.
|
||||
*
|
||||
* @param string $transient_key The transient key.
|
||||
* @return array An array containing 'message' and 'code'.
|
||||
*/
|
||||
public function extract_and_clear_transient_data( string $transient_key ): array {
|
||||
$data = get_transient( $transient_key );
|
||||
delete_transient( $transient_key );
|
||||
|
||||
return array(
|
||||
'message' => $data['message'] ?? null,
|
||||
'code' => $data['code'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render content for password detection page.
|
||||
*
|
||||
* @param \WP_User $user The user.
|
||||
* @param string $token The token.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_content( \WP_User $user, string $token ): void {
|
||||
$error_transient_key = Config::PREFIX . "_error_{$user->ID}";
|
||||
$success_transient_key = Config::PREFIX . "_success_{$user->ID}";
|
||||
|
||||
$error_data = $this->extract_and_clear_transient_data( $error_transient_key );
|
||||
$success_data = $this->extract_and_clear_transient_data( $success_transient_key );
|
||||
|
||||
$body_classes = 'password-detection-wrapper';
|
||||
if ( 'auth_code_success' === $success_data['code'] ) {
|
||||
$body_classes .= ' interim-login-success';
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php esc_html_e( 'Jetpack - Secure Your Account', 'jetpack-account-protection' ); ?></title>
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
<body class="<?php echo esc_attr( $body_classes ); ?>">
|
||||
<div class="password-detection-content">
|
||||
<?php
|
||||
$jetpack_logo = new Jetpack_Logo();
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $jetpack_logo->get_jp_emblem( true );
|
||||
?>
|
||||
<p class="password-detection-title"><?php echo $success_data['code'] === 'auth_code_success' ? esc_html__( 'Take action to stay secure', 'jetpack-account-protection' ) : esc_html__( 'Verify your identity', 'jetpack-account-protection' ); ?></p>
|
||||
<?php if ( $error_data['message'] ) : ?>
|
||||
<div class="error notice">
|
||||
<p class="notice-message"><?php echo esc_html( $error_data['message'] ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( $success_data['message'] ) : ?>
|
||||
<div class="success notice">
|
||||
<p class="notice-message"><?php echo esc_html( $success_data['message'] ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( $success_data['code'] === 'auth_code_success' ) : ?>
|
||||
<p><?php esc_html_e( "You're all set! You can now access your account.", 'jetpack-account-protection' ); ?></p>
|
||||
<p><?php esc_html_e( 'Please keep in mind that your current password was found in a public leak, which means your account might be at risk. It is highly recommended that you update your password.', 'jetpack-account-protection' ); ?></p>
|
||||
<div class="actions">
|
||||
<a href="<?php echo esc_url( admin_url( 'profile.php#password' ) ); ?>" class="action action-update-password">
|
||||
<?php esc_html_e( 'Create a new password', 'jetpack-account-protection' ); ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url( admin_url() ); ?>" class="action action-proceed">
|
||||
<?php esc_html_e( 'Proceed without updating', 'jetpack-account-protection' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Risks of using weak passwords link */
|
||||
esc_html__( 'Learn more about the %s and how to protect your account.', 'jetpack-account-protection' ),
|
||||
'<a class="risks-link" href="' . esc_url( Config::SUPPORT_LINK . '#risks-of-using-a-weak-password' ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'risks of using weak passwords', 'jetpack-account-protection' ) . '</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php else : ?>
|
||||
<p><?php esc_html_e( 'We\'ve noticed that your current password may have been compromised in a public leak. To keep your account safe, we\'ve added an extra layer of security.', 'jetpack-account-protection' ); ?></p>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Masked email address */
|
||||
esc_html__( 'We\'ve sent a code to %s. Please check your inbox and enter the code below to verify it\'s really you.', 'jetpack-account-protection' ),
|
||||
esc_html( $this->email_service->mask_email_address( $user->user_email ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<div class="actions">
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'verify_action', '_wpnonce_verify' ); ?>
|
||||
<input
|
||||
type="text"
|
||||
name="user_input"
|
||||
class="action-input"
|
||||
placeholder="<?php esc_attr_e( 'Enter verification code', 'jetpack-account-protection' ); ?>"
|
||||
required
|
||||
pattern="\d{6}"
|
||||
minlength="6"
|
||||
maxlength="6"
|
||||
inputmode="numeric"
|
||||
oninput="this.value = this.value.replace(/\D/g, '');"
|
||||
/>
|
||||
<button class="action action-verify" type="submit" name="verify"><?php esc_html_e( 'Verify', 'jetpack-account-protection' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
<?php if ( in_array( $error_data['code'], array( 'email_request_limit_exceeded', 'email_send_error' ), true ) ) : ?>
|
||||
<p class="account-recovery">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Jetpack support link */
|
||||
esc_html__( 'If you did not receive your authentication code, please try again later or %s now.', 'jetpack-account-protection' ),
|
||||
'<a class="risks-link" href="' . esc_url( wp_lostpassword_url() ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'reset your password', 'jetpack-account-protection' ) . '</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php else : ?>
|
||||
<p class="email-status">
|
||||
<span><?php esc_html_e( "Didn't get the code?", 'jetpack-account-protection' ); ?> </span>
|
||||
<a class="resend-email-link" href="<?php echo esc_url( $this->get_redirect_url( $token ) . '&resend_email=1&_wpnonce=' . wp_create_nonce( 'resend_email_nonce' ) ); ?>">
|
||||
<?php esc_html_e( 'Resend email', 'jetpack-account-protection' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php wp_footer(); ?>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
$this->exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user requires password protection.
|
||||
*
|
||||
* @param \WP_User $user The user object.
|
||||
* @param string $password The password.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function user_requires_protection( \WP_User $user, string $password ): bool {
|
||||
if ( ! user_can( $user, 'publish_posts' ) && ! user_can( $user, 'edit_published_posts' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter which determines whether or not password detection should be applied for the provided user.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*
|
||||
* @param bool $requires_protection Whether or not password detection should be applied.
|
||||
* @param \WP_User $user The user object to apply the filter against.
|
||||
*/
|
||||
|
||||
$user_requires_protection = apply_filters( 'jetpack_account_protection_user_requires_protection', true, $user );
|
||||
|
||||
if ( ! $user_requires_protection ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wp_check_password( $password, $user->user_pass, $user->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and store a consolidated transient for the user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $auth_code The auth code.
|
||||
*
|
||||
* @return string The generated token associated with the new transient data.
|
||||
*/
|
||||
private function generate_and_store_transient_data( int $user_id, string $auth_code ): string {
|
||||
$token = wp_generate_password( 32, false, false );
|
||||
|
||||
$data = array(
|
||||
'user_id' => $user_id,
|
||||
'auth_code' => $auth_code,
|
||||
'requests' => 1,
|
||||
);
|
||||
|
||||
$set_token_transient = set_transient( Config::PREFIX . "_{$token}", $data, Config::PASSWORD_DETECTION_EMAIL_SENT_EXPIRATION );
|
||||
$set_user_transient = set_transient( Config::PREFIX . "_last_valid_token_{$user_id}", $token, Config::PASSWORD_DETECTION_EMAIL_SENT_EXPIRATION );
|
||||
if ( ! $set_token_transient || ! $set_user_transient ) {
|
||||
$this->set_transient_error(
|
||||
$user_id,
|
||||
array(
|
||||
'code' => 'transient_error',
|
||||
'message' => __( 'Failed to set transient data. Please try again.', 'jetpack-account-protection' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the login page.
|
||||
*
|
||||
* @return never
|
||||
*/
|
||||
private function redirect_to_login() {
|
||||
$this->redirect_and_exit( wp_login_url() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get redirect URL.
|
||||
*
|
||||
* @param string $token The token.
|
||||
*
|
||||
* @return string The redirect URL.
|
||||
*/
|
||||
private function get_redirect_url( string $token ): string {
|
||||
return home_url( '/wp-login.php?action=password-detection&token=' . $token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle auth form submission.
|
||||
*
|
||||
* @param \WP_User $user The current user.
|
||||
* @param string $token The token.
|
||||
* @param string $auth_code The expected auth code.
|
||||
* @param string $user_input The user input.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function handle_auth_form_submission( \WP_User $user, string $token, string $auth_code, string $user_input ): void {
|
||||
if ( $auth_code && $auth_code === $user_input ) {
|
||||
$this->set_transient_success(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => 'auth_code_success',
|
||||
'message' => __( 'Authentication code verified successfully.', 'jetpack-account-protection' ),
|
||||
)
|
||||
);
|
||||
|
||||
delete_transient( Config::PREFIX . "_{$token}" );
|
||||
delete_transient( Config::PREFIX . "_last_valid_token_{$user->ID}" );
|
||||
wp_set_auth_cookie( $user->ID, true );
|
||||
wp_set_current_user( $user->ID );
|
||||
} else {
|
||||
$this->set_transient_error(
|
||||
$user->ID,
|
||||
array(
|
||||
'code' => 'auth_code_error',
|
||||
'message' => __( 'Authentication code verification failed. Please try again.', 'jetpack-account-protection' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a transient success message.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param array $success An array of the success code and message.
|
||||
* @param int $expiration The expiration time in seconds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_transient_success( int $user_id, array $success, int $expiration = 60 ): void {
|
||||
set_transient( Config::PREFIX . "_success_{$user_id}", $success, $expiration );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a transient error message.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param array $error An array of the error code and message.
|
||||
* @param int $expiration The expiration time in seconds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_transient_error( int $user_id, array $error, int $expiration = 60 ): void {
|
||||
set_transient( Config::PREFIX . "_error_{$user_id}", $error, $expiration );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the password detection page styles.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_styles(): void {
|
||||
global $pagenow;
|
||||
if ( ! isset( $pagenow ) || $pagenow !== 'wp-login.php' ) {
|
||||
return;
|
||||
}
|
||||
// No nonce verification necessary - reading only
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( isset( $_GET['action'] ) && $_GET['action'] === 'password-detection' ) {
|
||||
wp_enqueue_style(
|
||||
'password-detection-styles',
|
||||
plugin_dir_url( __FILE__ ) . 'css/password-detection.css',
|
||||
array(),
|
||||
Account_Protection::PACKAGE_VERSION
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used to define Password Manager.
|
||||
*
|
||||
* @package automattic/jetpack-account-protection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Account_Protection;
|
||||
|
||||
/**
|
||||
* Class Password_Manager
|
||||
*/
|
||||
class Password_Manager {
|
||||
/**
|
||||
* Validaton service instance
|
||||
*
|
||||
* @var Validation_Service
|
||||
*/
|
||||
private $validation_service;
|
||||
|
||||
/**
|
||||
* Validation_Service constructor.
|
||||
*
|
||||
* @param ?Validation_Service $validation_service Password manager instance.
|
||||
*/
|
||||
public function __construct( ?Validation_Service $validation_service = null ) {
|
||||
$this->validation_service = $validation_service ?? new Validation_Service();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the profile update.
|
||||
*
|
||||
* @param \WP_Error $errors The error object.
|
||||
* @param bool $update Whether the user is being updated.
|
||||
* @param \stdClass $user A copy of the new user object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function validate_profile_update( \WP_Error $errors, bool $update, \stdClass $user ): void {
|
||||
if ( empty( $user->user_pass ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If bypass is enabled, do not validate the password
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( isset( $_POST['pw_weak'] ) && 'on' === $_POST['pw_weak'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$core_validation_errors = $errors->get_error_messages( 'pass' );
|
||||
$jetpack_validation_errors = $this->validation_service->get_validation_errors( $user->user_pass, true, $user );
|
||||
$validation_errors = array_diff( $jetpack_validation_errors, $core_validation_errors );
|
||||
|
||||
foreach ( $validation_errors as $validation_error ) {
|
||||
$errors->add( 'pass', $validation_error, array( 'form-field' => 'pass1' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the password reset.
|
||||
*
|
||||
* @param \WP_Error $errors The error object.
|
||||
* @param \WP_User|\WP_Error $user The user object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function validate_password_reset( \WP_Error $errors, $user ): void {
|
||||
if ( is_wp_error( $user ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( empty( $_POST['pass1'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If bypass is enabled, do not validate the password
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( isset( $_POST['pw_weak'] ) && 'on' === $_POST['pw_weak'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
$password = wp_unslash( $_POST['pass1'] );
|
||||
|
||||
$core_validation_errors = $errors->get_error_messages( 'pass' );
|
||||
$jetpack_validation_errors = $this->validation_service->get_validation_errors( $password );
|
||||
$validation_errors = array_diff( $jetpack_validation_errors, $core_validation_errors );
|
||||
|
||||
foreach ( $validation_errors as $validation_error ) {
|
||||
$errors->add( 'pass', $validation_error, array( 'form-field' => 'pass1' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the profile update.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param \WP_User|\stdClass|null $old_user_data Object containing user data prior to update.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function on_profile_update( int $user_id, $old_user_data ): void {
|
||||
if ( ! is_object( $old_user_data ) || empty( $old_user_data->user_pass ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( isset( $_POST['action'] ) && $_POST['action'] === 'update' ) {
|
||||
$this->save_recent_password_hash( $user_id, $old_user_data->user_pass );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the password reset.
|
||||
*
|
||||
* @param \WP_User|\stdClass|null $user The user object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function on_password_reset( $user ): void {
|
||||
if ( ! is_object( $user ) || ! isset( $user->ID ) || empty( $user->user_pass ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->save_recent_password_hash( $user->ID, $user->user_pass );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the new password hash to the user's recent passwords list.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $password_hash The password hash to store.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save_recent_password_hash( int $user_id, string $password_hash ): void {
|
||||
$recent_passwords = get_user_meta( $user_id, Config::RECENT_PASSWORD_HASHES_USER_META_KEY, true );
|
||||
|
||||
if ( ! is_array( $recent_passwords ) ) {
|
||||
$recent_passwords = array();
|
||||
}
|
||||
|
||||
if ( in_array( $password_hash, $recent_passwords, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the new hashed password and keep only the last 10
|
||||
array_unshift( $recent_passwords, $password_hash );
|
||||
$recent_passwords = array_slice( $recent_passwords, 0, Config::PASSWORD_MANAGER_RECENT_PASSWORDS_LIMIT );
|
||||
|
||||
update_user_meta( $user_id, Config::RECENT_PASSWORD_HASHES_USER_META_KEY, $recent_passwords );
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used to define Password Strength Meter.
|
||||
*
|
||||
* @package automattic/jetpack-account-protection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Account_Protection;
|
||||
|
||||
use Automattic\Jetpack\Assets\Logo as Jetpack_Logo;
|
||||
|
||||
/**
|
||||
* Class Password_Strength_Meter
|
||||
*/
|
||||
class Password_Strength_Meter {
|
||||
/**
|
||||
* Validaton service instance
|
||||
*
|
||||
* @var Validation_Service
|
||||
*/
|
||||
private $validation_service;
|
||||
|
||||
/**
|
||||
* Validation_Service constructor.
|
||||
*
|
||||
* @param ?Validation_Service $validation_service Password manager instance.
|
||||
*/
|
||||
public function __construct( ?Validation_Service $validation_service = null ) {
|
||||
$this->validation_service = $validation_service ?? new Validation_Service();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method for nonce verification.
|
||||
*
|
||||
* @param string $nonce Nonce value.
|
||||
* @param string $action Nonce action.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function verify_nonce( string $nonce, string $action ): bool {
|
||||
return wp_verify_nonce( $nonce, $action );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method for sending a JSON error response.
|
||||
*
|
||||
* @param string $message The error message.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function send_json_error( string $message ): void {
|
||||
// @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
|
||||
wp_send_json_error( array( 'message' => $message ), null, JSON_UNESCAPED_SLASHES );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method for sending a JSON success response.
|
||||
*
|
||||
* @param array $data The data to send.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function send_json_success( array $data ): void {
|
||||
// @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
|
||||
wp_send_json_success( $data, null, JSON_UNESCAPED_SLASHES );
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX endpoint for password validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function validate_password_ajax(): void {
|
||||
// phpcs:disable WordPress.Security.NonceVerification
|
||||
if ( ! isset( $_POST['password'] ) ) {
|
||||
$this->send_json_error( __( 'No password provided.', 'jetpack-account-protection' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! isset( $_POST['nonce'] ) || ! $this->verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'validate_password_nonce' ) ) {
|
||||
$this->send_json_error( __( 'Invalid nonce.', 'jetpack-account-protection' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
$user_specific = false;
|
||||
if ( isset( $_POST['user_specific'] ) ) {
|
||||
$user_specific = filter_var( sanitize_text_field( wp_unslash( $_POST['user_specific'] ) ), FILTER_VALIDATE_BOOLEAN );
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
$password = wp_unslash( $_POST['password'] );
|
||||
// phpcs:enable WordPress.Security.NonceVerification
|
||||
$state = $this->validation_service->get_validation_state( $password, $user_specific );
|
||||
|
||||
$this->send_json_success( array( 'state' => $state ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the password strength meter script on the profile page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_jetpack_password_strength_meter_profile_script(): void {
|
||||
global $pagenow;
|
||||
|
||||
if ( ! isset( $pagenow ) || ! in_array( $pagenow, array( 'profile.php', 'user-new.php', 'user-edit.php' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->enqueue_script();
|
||||
$this->enqueue_styles();
|
||||
|
||||
// Only profile page should run user specific checks.
|
||||
$this->localize_jetpack_data( 'profile.php' === $pagenow );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the password strength meter script on the reset password page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_jetpack_password_strength_meter_reset_script(): void {
|
||||
// No nonce verification necessary as the action includes a robust verification process
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( isset( $_GET['action'] ) && ( 'rp' === $_GET['action'] || 'resetpass' === $_GET['action'] ) ) {
|
||||
$this->enqueue_script();
|
||||
$this->enqueue_styles();
|
||||
$this->localize_jetpack_data();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize the Jetpack data for the password strength meter.
|
||||
*
|
||||
* @param bool $user_specific Whether or not to run user specific checks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function localize_jetpack_data( bool $user_specific = false ): void {
|
||||
$jetpack_logo = new Jetpack_Logo();
|
||||
|
||||
wp_localize_script(
|
||||
'jetpack-password-strength-meter',
|
||||
'jetpackData',
|
||||
array(
|
||||
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'validate_password_nonce' ),
|
||||
'userSpecific' => $user_specific,
|
||||
'logo' => htmlspecialchars( $jetpack_logo->get_jp_emblem( true ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ),
|
||||
'validationInitialState' => $this->validation_service->get_validation_initial_state( $user_specific ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the password strength meter script.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_script(): void {
|
||||
wp_enqueue_script(
|
||||
'jetpack-password-strength-meter',
|
||||
plugin_dir_url( __FILE__ ) . 'js/jetpack-password-strength-meter.js',
|
||||
array( 'jquery' ),
|
||||
Account_Protection::PACKAGE_VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the password strength meter styles.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_styles(): void {
|
||||
wp_enqueue_style(
|
||||
'strength-meter-styles',
|
||||
plugin_dir_url( __FILE__ ) . 'css/strength-meter.css',
|
||||
array(),
|
||||
Account_Protection::PACKAGE_VERSION
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used to manage settings related to Account Protection.
|
||||
*
|
||||
* @package automattic/jetpack-account-protection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Account_Protection;
|
||||
|
||||
/**
|
||||
* Account Protection Settings
|
||||
*/
|
||||
class Settings {
|
||||
/**
|
||||
* Account protection instance.
|
||||
*
|
||||
* @var Account_Protection
|
||||
*/
|
||||
private $account_protection;
|
||||
|
||||
/**
|
||||
* Constructor for dependency injection.
|
||||
*
|
||||
* @param ?Account_Protection|null $account_protection Account protection dependency.
|
||||
*/
|
||||
public function __construct( ?Account_Protection $account_protection = null ) {
|
||||
$this->account_protection = $account_protection ?? Account_Protection::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get account protection settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get() {
|
||||
$settings = array(
|
||||
'isEnabled' => $this->account_protection->is_enabled(),
|
||||
'isSupported' => $this->account_protection->is_supported_environment(),
|
||||
'hasUnsupportedJetpackVersion' => $this->account_protection->has_unsupported_jetpack_version(),
|
||||
);
|
||||
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,326 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used to define Validation Service.
|
||||
*
|
||||
* @package automattic/jetpack-account-protection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Account_Protection;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
|
||||
/**
|
||||
* Class Validation_Service
|
||||
*/
|
||||
class Validation_Service {
|
||||
|
||||
/**
|
||||
* Connection manager dependency.
|
||||
*
|
||||
* @var Connection_Manager
|
||||
*/
|
||||
private $connection_manager;
|
||||
|
||||
/**
|
||||
* Constructor for dependency injection.
|
||||
*
|
||||
* @param Connection_Manager|null $connection_manager Connection manager dependency.
|
||||
*/
|
||||
public function __construct(
|
||||
?Connection_Manager $connection_manager = null
|
||||
) {
|
||||
$this->connection_manager = $connection_manager ?? new Connection_Manager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dependency decoupling so we can test this class.
|
||||
*
|
||||
* @param string $password_prefix The password prefix to be checked.
|
||||
* @return array|\WP_Error
|
||||
*/
|
||||
protected function request_suffixes( string $password_prefix ) {
|
||||
return Client::wpcom_json_api_request_as_blog(
|
||||
'/jetpack-protect-weak-password/' . $password_prefix,
|
||||
'2',
|
||||
array( 'method' => 'GET' ),
|
||||
null,
|
||||
'wpcom'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return validation initial state.
|
||||
*
|
||||
* @param bool $user_specific Whether or not to include user specific checks.
|
||||
*
|
||||
* @return array An array of all validation statuses and messages.
|
||||
*/
|
||||
public function get_validation_initial_state( $user_specific ): array {
|
||||
$base_conditions = array(
|
||||
'core' => array(
|
||||
'status' => null,
|
||||
'message' => __( 'Strong password', 'jetpack-account-protection' ),
|
||||
'info' => __( 'Passwords should meet WordPress core security requirements to enhance account protection.', 'jetpack-account-protection' ),
|
||||
),
|
||||
'contains_backslash' => array(
|
||||
'status' => null,
|
||||
'message' => __( "Doesn't contain a backslash (\\) character", 'jetpack-account-protection' ),
|
||||
'info' => null,
|
||||
),
|
||||
'invalid_length' => array(
|
||||
'status' => null,
|
||||
'message' => __( 'Between 6 and 150 characters', 'jetpack-account-protection' ),
|
||||
'info' => null,
|
||||
),
|
||||
'leaked' => array(
|
||||
'status' => null,
|
||||
'message' => __( 'Not a leaked password', 'jetpack-account-protection' ),
|
||||
'info' => __( 'If found in a public breach, this password may already be known to attackers.', 'jetpack-account-protection' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( ! $user_specific ) {
|
||||
return $base_conditions;
|
||||
}
|
||||
|
||||
$user_specific_conditions = array(
|
||||
'matches_user_data' => array(
|
||||
'status' => null,
|
||||
'message' => __( "Doesn't match existing user data", 'jetpack-account-protection' ),
|
||||
'info' => __( 'Using a password similar to your username or email makes it easier to guess.', 'jetpack-account-protection' ),
|
||||
),
|
||||
'recent' => array(
|
||||
'status' => null,
|
||||
'message' => __( 'Not used recently', 'jetpack-account-protection' ),
|
||||
'info' => __( 'Reusing old passwords may increase security risks. A fresh password improves protection.', 'jetpack-account-protection' ),
|
||||
),
|
||||
);
|
||||
|
||||
return array_merge( $base_conditions, $user_specific_conditions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return validation state - client-side.
|
||||
*
|
||||
* @param string $password The password to check.
|
||||
* @param bool $user_specific Whether or not to run user specific checks.
|
||||
*
|
||||
* @return array An array of the status of each check.
|
||||
*/
|
||||
public function get_validation_state( string $password, $user_specific ): array {
|
||||
$validation_state = $this->get_validation_initial_state( $user_specific );
|
||||
|
||||
$validation_state['contains_backslash']['status'] = $this->contains_backslash( $password );
|
||||
$validation_state['invalid_length']['status'] = $this->is_invalid_length( $password );
|
||||
$validation_state['leaked']['status'] = $this->is_leaked_password( $password );
|
||||
|
||||
if ( ! $user_specific ) {
|
||||
return $validation_state;
|
||||
}
|
||||
|
||||
// Run checks on existing user data
|
||||
$user = wp_get_current_user();
|
||||
$validation_state['matches_user_data']['status'] = $this->matches_user_data( $user, $password );
|
||||
$validation_state['recent']['status'] = $this->is_recent_password_hash( $user, $password );
|
||||
|
||||
return $validation_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all validation errors - server-side.
|
||||
*
|
||||
* @param string $password The password to check.
|
||||
* @param bool $user_specific Whether or not to run user specific checks.
|
||||
* @param \stdClass|null $user The user data or null.
|
||||
*
|
||||
* @return array The validation errors (if any).
|
||||
*/
|
||||
public function get_validation_errors( string $password, $user_specific = false, $user = null ): array {
|
||||
$errors = array();
|
||||
|
||||
if ( empty( $password ) ) {
|
||||
$errors[] = __( '<strong>Error:</strong> The password cannot be a space or all spaces.', 'jetpack-account-protection' );
|
||||
}
|
||||
|
||||
if ( $this->contains_backslash( $password ) ) {
|
||||
$errors[] = __( '<strong>Error:</strong> Passwords may not contain the character "\\".', 'jetpack-account-protection' );
|
||||
}
|
||||
|
||||
if ( $this->is_invalid_length( $password ) ) {
|
||||
$errors[] = __( '<strong>Error:</strong> The password must be between 6 and 150 characters.', 'jetpack-account-protection' );
|
||||
}
|
||||
|
||||
if ( $this->is_leaked_password( $password ) ) {
|
||||
$errors[] = __( '<strong>Error:</strong> The password was found in a public leak.', 'jetpack-account-protection' );
|
||||
}
|
||||
|
||||
// Skip user-specific checks during password reset
|
||||
if ( $user_specific ) {
|
||||
// Run checks on new user data
|
||||
if ( $this->matches_user_data( $user, $password ) ) {
|
||||
$errors[] = __( '<strong>Error:</strong> The password matches new user data.', 'jetpack-account-protection' );
|
||||
}
|
||||
if ( $this->is_recent_password_hash( $user, $password ) ) {
|
||||
$errors[] = __( '<strong>Error:</strong> The password was used recently.', 'jetpack-account-protection' );
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password contains a backslash.
|
||||
*
|
||||
* @param string $password The password to check.
|
||||
*
|
||||
* @return bool True if the password contains a backslash, false otherwise.
|
||||
*/
|
||||
public function contains_backslash( string $password ): bool {
|
||||
return strpos( $password, '\\' ) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password length is within the allowed range.
|
||||
*
|
||||
* @param string $password The password to check.
|
||||
*
|
||||
* @return bool True if the password is between 6 and 150 characters, false otherwise.
|
||||
*/
|
||||
public function is_invalid_length( string $password ): bool {
|
||||
$length = strlen( $password );
|
||||
return $length < Config::VALIDATION_SERVICE_MIN_LENGTH || $length > Config::VALIDATION_SERVICE_MAX_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password matches any user data.
|
||||
*
|
||||
* @param \WP_User|\stdClass|null $user The user.
|
||||
* @param string $password The password to check.
|
||||
*
|
||||
* @return bool True if the password matches any user data, false otherwise.
|
||||
*/
|
||||
public function matches_user_data( $user, string $password ): bool {
|
||||
if ( ! $user ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$email_parts = explode( '@', $user->user_email ); // test@example.com
|
||||
$email_username = $email_parts[0]; // 'test'
|
||||
$email_domain = $email_parts[1]; // 'example.com'
|
||||
$email_provider = explode( '.', $email_domain )[0]; // 'example'
|
||||
|
||||
$user_data = array(
|
||||
$user->user_login ?? '',
|
||||
$user->display_name ?? '',
|
||||
$user->first_name ?? '',
|
||||
$user->last_name ?? '',
|
||||
$user->user_email ?? '',
|
||||
$email_username ?? '',
|
||||
$email_provider ?? '',
|
||||
$user->nickname ?? '',
|
||||
);
|
||||
|
||||
$password_lower = strtolower( $password );
|
||||
|
||||
foreach ( $user_data as $data ) {
|
||||
// Skip if $data is 3 characters or less.
|
||||
if ( strlen( $data ) <= 3 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! empty( $data ) && strpos( $password_lower, strtolower( $data ) ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password is in the list of compromised/common passwords.
|
||||
*
|
||||
* @param string $password The password to check.
|
||||
*
|
||||
* @return bool True if the password is in the list of compromised/common passwords, false otherwise.
|
||||
*/
|
||||
public function is_leaked_password( string $password ): bool {
|
||||
if ( ! $this->connection_manager->is_connected() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hashed_password = sha1( $password );
|
||||
$password_prefix = substr( $hashed_password, 0, 5 );
|
||||
|
||||
$response = $this->request_suffixes( $password_prefix );
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code || empty( $response['body'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
$password_suffix = substr( $hashed_password, 5 );
|
||||
if ( in_array( $password_suffix, $body['compromised'] ?? array(), true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( in_array( $password_suffix, $body['common'] ?? array(), true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password is the current password for the user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $password The password to check.
|
||||
*
|
||||
* @return bool True if the password is the current password, false otherwise.
|
||||
*/
|
||||
public function is_current_password( int $user_id, string $password ): bool {
|
||||
$user = get_userdata( $user_id );
|
||||
if ( ! $user ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wp_check_password( $password, $user->user_pass, $user->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password has been used recently by the user.
|
||||
*
|
||||
* @param \WP_User|\stdClass $user The user data.
|
||||
* @param string $password The password to check.
|
||||
*
|
||||
* @return bool True if the password was recently used, false otherwise.
|
||||
*/
|
||||
public function is_recent_password_hash( $user, string $password ): bool {
|
||||
// Skip on user creation
|
||||
if ( empty( $user->ID ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user_data = $user instanceof \WP_User ? $user : get_userdata( $user->ID );
|
||||
if ( $this->is_current_password( $user_data->ID, $password ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$recent_passwords = get_user_meta( $user->ID, Config::RECENT_PASSWORD_HASHES_USER_META_KEY, true );
|
||||
if ( empty( $recent_passwords ) || ! is_array( $recent_passwords ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $recent_passwords as $old_hashed_password ) {
|
||||
if ( wp_check_password( $password, $old_hashed_password ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
.password-detection-wrapper {
|
||||
background-color: #f0f0f1;
|
||||
min-width: 0;
|
||||
margin: 30px;
|
||||
color: #3c434a;
|
||||
font-family: -apple-system, system-ui, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.password-detection-content {
|
||||
background: #fff;
|
||||
max-width: 420px;
|
||||
margin: auto;
|
||||
padding: 26px 24px;
|
||||
font-weight: 400;
|
||||
overflow: hidden;
|
||||
border: 1px solid #c3c4c7;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
||||
|
||||
#jetpack-logo__icon {
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.password-detection-title {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
border-radius: 2px;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.action-input {
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
text-indent: 8px;
|
||||
|
||||
&::placeholder {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.action-verify,
|
||||
.action-update-password {
|
||||
margin-top: 10px;
|
||||
background-color: #00e;
|
||||
border: 2px solid #00e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.action-proceed {
|
||||
background-color: #fff;
|
||||
border: 2px solid #00e;
|
||||
color: #00e;
|
||||
}
|
||||
|
||||
a.risks-link,
|
||||
a.resend-email-link {
|
||||
color: #00e;
|
||||
}
|
||||
|
||||
.email-status {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.notice {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.notice-message {
|
||||
text-align: center;
|
||||
margin: 7px 0;
|
||||
}
|
||||
|
||||
.error {
|
||||
background: #facfd2;
|
||||
border: 2px solid #e65054;
|
||||
color: #e65054;
|
||||
}
|
||||
|
||||
.success {
|
||||
background: #d0e6b8;
|
||||
border: 2px solid #069e08;
|
||||
color: #069e08;
|
||||
}
|
||||
|
||||
@ -0,0 +1,126 @@
|
||||
#login .wp-pwd,
|
||||
.user-pass1-wrap {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.validation-checklist {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.validation-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 0;
|
||||
|
||||
.validation-icon {
|
||||
display: inline-block;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNzY3Njc2IiBzdHJva2Utd2lkdGg9IjIiIG9wYWNpdHk9IjAuMyIvPgogIDxwYXRoIGQ9Ik0xMiAyYTEwIDEwIDAgMCAxIDAgMjAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzc2NzY3NiIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiPgogICAgPGFuaW1hdGVUcmFuc2Zvcm0gYXR0cmlidXRlTmFtZT0idHJhbnNmb3JtIiB0eXBlPSJyb3RhdGUiIGZyb209IjAgMTIgMTIiIHRvPSIzNjAgMTIgMTIiIGR1cj0iMXMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIi8+CiAgPC9wYXRoPgo8L3N2Zz4=);
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.check {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIgZmlsbD0iIzAwODcxMCIvPgogIDxwYXRoIGQ9Ik0xNi43IDcuMWwtNi4zIDguNS0zLjMtMi41LS45IDEuMiA0LjUgMy40TDE3LjkgOHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPg==);
|
||||
}
|
||||
|
||||
.cross {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIgZmlsbD0iI0U2NTA1NCIvPgogIDxwYXRoIGQ9Ik04IDhsOCA4TTE2IDhsLTggOCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KPC9zdmc+);
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
margin-top: 0;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.info-popover {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4IiBmaWxsPSIjQTdBQUFEIj4KICA8cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6bTEtMTNoLTJ2MmgyVjd6bTAgNGgtMnY2aDJ2LTZ6Ii8+Cjwvc3ZnPg==);
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
|
||||
.popover {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: #333;
|
||||
color: #fff;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
white-space: normal;
|
||||
width: 150px;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
z-index: 10;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-top: 6px solid #333;
|
||||
}
|
||||
|
||||
#your-profile .strength-meter,
|
||||
#createuser .strength-meter {
|
||||
margin: 0 1px;
|
||||
}
|
||||
|
||||
.strength-meter {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 30px;
|
||||
padding: 0 16px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 0 0 4px 4px;
|
||||
background-color: #c3c4c7;
|
||||
}
|
||||
|
||||
.strength-meter .strength {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.branding {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
.powered-by {
|
||||
font-size: 12px;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#jetpack-logo__icon {
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,401 @@
|
||||
/* global jQuery, jetpackData */
|
||||
|
||||
jQuery( document ).ready( function ( $ ) {
|
||||
const UIComponents = {
|
||||
core: {
|
||||
passwordInput: $( '#pass1' ),
|
||||
passwordStrengthResults: $( '#pass-strength-result' ),
|
||||
weakPasswordConfirmation: $( '.pw-weak' ),
|
||||
weakPasswordConfirmationCheckbox: $( '.pw-weak input[type="checkbox"]' ),
|
||||
submitButtons: $( '#submit, #createusersub, #wp-submit' ),
|
||||
},
|
||||
passwordValidationStatus: $( '<div>', { id: 'password-validation-status' } ),
|
||||
validationCheckList: $( '<ul>', { class: 'validation-checklist' } ),
|
||||
strengthMeter: {},
|
||||
validationChecklistItems: {},
|
||||
};
|
||||
|
||||
let currentAjaxRequest = null;
|
||||
|
||||
/**
|
||||
* Apply initial validation UI structure and styling
|
||||
*/
|
||||
function initializeValidationUI() {
|
||||
initializeForm();
|
||||
initializeStrengthMeter();
|
||||
initializeValidationChecklist();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and append the initial strength meter state
|
||||
*/
|
||||
function initializeForm() {
|
||||
const { passwordInput, passwordStrengthResults } = UIComponents.core;
|
||||
|
||||
passwordInput.css( {
|
||||
'border-color': '#8C8F94',
|
||||
'border-radius': '4px 4px 0 0',
|
||||
} );
|
||||
|
||||
passwordStrengthResults.hide();
|
||||
passwordInput.after( UIComponents.passwordValidationStatus );
|
||||
UIComponents.passwordValidationStatus.append( UIComponents.validationCheckList );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and append the initial strength meter state
|
||||
*/
|
||||
function initializeStrengthMeter() {
|
||||
const strengthMeterWrapper = $( '<div>', {
|
||||
class: 'strength-meter',
|
||||
'aria-live': 'polite',
|
||||
} );
|
||||
|
||||
const strengthText = $( '<p>', {
|
||||
class: 'strength',
|
||||
text: 'Validating...',
|
||||
} );
|
||||
|
||||
const branding = $( '<div>', { class: 'branding' } )
|
||||
.append( $( '<p>', { class: 'powered-by', text: 'Powered by ' } ) )
|
||||
.append( jetpackData.logo );
|
||||
|
||||
strengthMeterWrapper.append( strengthText, branding );
|
||||
UIComponents.validationCheckList.before( strengthMeterWrapper );
|
||||
|
||||
UIComponents.strengthMeter = {
|
||||
wrapper: strengthMeterWrapper,
|
||||
text: strengthText,
|
||||
branding,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and append the initial validation checklist state
|
||||
*/
|
||||
function initializeValidationChecklist() {
|
||||
Object.entries( jetpackData.validationInitialState ).forEach( ( [ key, value ] ) => {
|
||||
const listItem = $( '<li>', { class: 'validation-item', 'data-key': key } );
|
||||
|
||||
// Hide the core and backslash validation items by default
|
||||
if ( [ 'core', 'contains_backslash' ].includes( key ) ) {
|
||||
listItem.hide();
|
||||
}
|
||||
|
||||
const validationIcon = $( '<span>', {
|
||||
class: 'validation-icon',
|
||||
} );
|
||||
|
||||
const validationMessage = $( '<p>', {
|
||||
text: value.message,
|
||||
class: 'validation-message',
|
||||
} );
|
||||
|
||||
const infoIconPopover = value.info ? createInfoIconPopover( value.info ) : null;
|
||||
listItem.append( validationIcon, validationMessage, infoIconPopover );
|
||||
UIComponents.validationCheckList.append( listItem );
|
||||
|
||||
UIComponents.validationChecklistItems[ key ] = {
|
||||
icon: validationIcon,
|
||||
text: validationMessage,
|
||||
item: listItem,
|
||||
};
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Debounce function to limit the number of requests
|
||||
* @param {Function} func - The function to debounce
|
||||
* @param {number} delay - The delay in milliseconds
|
||||
*
|
||||
* @return {Function} - The debounced function
|
||||
*/
|
||||
function debounce( func, delay ) {
|
||||
let timer;
|
||||
return function () {
|
||||
clearTimeout( timer );
|
||||
timer = setTimeout( () => func.apply( this, arguments ), delay );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind events to the UI components
|
||||
*/
|
||||
function bindEvents() {
|
||||
const { passwordInput } = UIComponents.core;
|
||||
|
||||
passwordInput.on( 'input', debounce( validatePassword, 250 ) );
|
||||
passwordInput.on( 'pwupdate', validatePassword );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the current password input
|
||||
*/
|
||||
function validatePassword() {
|
||||
const { passwordInput, passwordStrengthResults } = UIComponents.core;
|
||||
|
||||
const password = passwordInput.val();
|
||||
|
||||
if ( currentAjaxRequest ) {
|
||||
const oldRequest = currentAjaxRequest;
|
||||
currentAjaxRequest = null;
|
||||
oldRequest.abort();
|
||||
}
|
||||
|
||||
if ( ! password?.trim() ) {
|
||||
updateValidationUI( 'empty' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure core strength meter is hidden
|
||||
passwordStrengthResults.hide();
|
||||
|
||||
updateValidationUI( 'loading' );
|
||||
|
||||
currentAjaxRequest = $.ajax( {
|
||||
url: jetpackData.ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'validate_password_ajax',
|
||||
nonce: jetpackData.nonce,
|
||||
password: password,
|
||||
user_specific: jetpackData.userSpecific,
|
||||
},
|
||||
success: handleValidationResponse,
|
||||
error: handleValidationError,
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the password validation response.
|
||||
* @param {object} response - The response object.
|
||||
*/
|
||||
function handleValidationResponse( response ) {
|
||||
currentAjaxRequest = null;
|
||||
|
||||
if ( response.success ) {
|
||||
updateValidationUI( 'results', response.data.state );
|
||||
} else {
|
||||
restoreCoreStrengthMeter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles validation errors.
|
||||
* @param {object} jqXHR - The jqXHR object.
|
||||
* @param {any} textStatus - The status of the request.
|
||||
*/
|
||||
function handleValidationError( jqXHR, textStatus ) {
|
||||
if ( textStatus !== 'abort' ) {
|
||||
restoreCoreStrengthMeter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the core validation state
|
||||
* @return {boolean} - Whether the core validation failed
|
||||
*/
|
||||
function getCoreValidationState() {
|
||||
const corePasswordStrengthResultsClass =
|
||||
UIComponents.core.passwordStrengthResults.attr( 'class' ) || '';
|
||||
|
||||
return ! (
|
||||
corePasswordStrengthResultsClass.includes( 'strong' ) ||
|
||||
corePasswordStrengthResultsClass.includes( 'good' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Update the validation UI based on the current state
|
||||
* @param {string} state - The current validation state
|
||||
* @param {object} validationState - Object containing validation state
|
||||
*/
|
||||
function updateValidationUI( state, validationState ) {
|
||||
if ( state === 'empty' ) {
|
||||
renderEmptyState();
|
||||
return;
|
||||
}
|
||||
|
||||
UIComponents.passwordValidationStatus.show();
|
||||
|
||||
if ( state === 'loading' ) {
|
||||
renderLoadingState();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( validationState ) {
|
||||
renderResultsState( validationState );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the empty input state
|
||||
*/
|
||||
function renderEmptyState() {
|
||||
const { weakPasswordConfirmation, passwordInput } = UIComponents.core;
|
||||
|
||||
weakPasswordConfirmation.hide();
|
||||
passwordInput.css( {
|
||||
'border-color': '#8C8F94',
|
||||
'border-radius': '4px',
|
||||
} );
|
||||
|
||||
UIComponents.passwordValidationStatus.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the loading state
|
||||
*/
|
||||
function renderLoadingState() {
|
||||
renderFormLoadingState();
|
||||
renderStrengthMeterLoadingState();
|
||||
renderValidationChecklistLoadingState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the form loading state
|
||||
*/
|
||||
function renderFormLoadingState() {
|
||||
const { submitButtons, passwordInput } = UIComponents.core;
|
||||
|
||||
submitButtons.prop( 'disabled', true );
|
||||
passwordInput.css( {
|
||||
'border-color': '#C3C4C7',
|
||||
'border-radius': '4px 4px 0px 0px',
|
||||
} );
|
||||
|
||||
UIComponents.passwordValidationStatus.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the strength meter loading state
|
||||
*/
|
||||
function renderStrengthMeterLoadingState() {
|
||||
const { wrapper, text } = UIComponents.strengthMeter;
|
||||
|
||||
text.text( 'Validating...' );
|
||||
wrapper.css( 'background-color', '#C3C4C7' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the validation checklist loading state
|
||||
*/
|
||||
function renderValidationChecklistLoadingState() {
|
||||
Object.entries( UIComponents.validationChecklistItems ).forEach( ( [ key, itemData ] ) => {
|
||||
const { icon, text, item } = itemData;
|
||||
|
||||
icon.removeClass( 'check cross' );
|
||||
text.css( { color: '#3C434A' } );
|
||||
|
||||
// Re-hide the core and contains_backslash items
|
||||
if ( [ 'core', 'contains_backslash' ].includes( key ) ) {
|
||||
item.hide();
|
||||
}
|
||||
} );
|
||||
|
||||
UIComponents.strengthMeter.text.text( 'Validating...' );
|
||||
UIComponents.strengthMeter.wrapper.css( 'background-color', '#C3C4C7' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the validation results state
|
||||
* @param {object} validationState - Object containing validation state
|
||||
*/
|
||||
function renderResultsState( validationState ) {
|
||||
validationState.core.status = getCoreValidationState();
|
||||
const isPasswordStrong = Object.values( validationState ).every( item => ! item.status );
|
||||
const color = isPasswordStrong ? '#9DD977' : '#FFABAF';
|
||||
const failedValidationKeys = ! isPasswordStrong
|
||||
? Object.keys( validationState ).filter( key => validationState[ key ].status )
|
||||
: [];
|
||||
|
||||
renderFormResultsState( isPasswordStrong, color );
|
||||
renderStengthMeterResultsState( isPasswordStrong, color );
|
||||
renderValidationChecklistResultsState( failedValidationKeys );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the form elements based on the current password strength
|
||||
* @param {boolean} isPasswordStrong - Whether the password is strong
|
||||
* @param {string} color - The color to apply to the form elements
|
||||
*/
|
||||
function renderFormResultsState( isPasswordStrong, color ) {
|
||||
const {
|
||||
passwordInput,
|
||||
weakPasswordConfirmation,
|
||||
weakPasswordConfirmationCheckbox,
|
||||
submitButtons,
|
||||
} = UIComponents.core;
|
||||
passwordInput.css( { 'border-color': color, 'border-radius': '4px 4px 0px 0px' } );
|
||||
|
||||
weakPasswordConfirmation.css( 'display', isPasswordStrong ? 'none' : 'table-row' );
|
||||
submitButtons.prop(
|
||||
'disabled',
|
||||
! isPasswordStrong && ! weakPasswordConfirmationCheckbox.prop( 'checked' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Update the strength meter based on the current password strength
|
||||
* @param {boolean} isPasswordStrong - Whether the password is strong
|
||||
* @param {string} color - The color to apply to the strength meter
|
||||
*/
|
||||
function renderStengthMeterResultsState( isPasswordStrong, color ) {
|
||||
const { wrapper, text } = UIComponents.strengthMeter;
|
||||
|
||||
text.text( isPasswordStrong ? 'Strong' : 'Weak' );
|
||||
wrapper.css( 'background-color', color );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Update the validation checklist based on the failed validation keys
|
||||
* @param {Array} failedValidationKeys - Array containing failed validation keys
|
||||
*/
|
||||
function renderValidationChecklistResultsState( failedValidationKeys ) {
|
||||
Object.entries( UIComponents.validationChecklistItems ).forEach( ( [ key, itemData ] ) => {
|
||||
const { icon, text, item } = itemData;
|
||||
const validationFailed = failedValidationKeys.includes( key );
|
||||
|
||||
icon.attr( 'class', `validation-icon ${ validationFailed ? 'cross' : 'check' }` );
|
||||
text.css( { color: validationFailed ? '#E65054' : '#008710' } );
|
||||
|
||||
// Display the core and backslash validation items they fail
|
||||
if ( [ 'core', 'contains_backslash' ].includes( key ) ) {
|
||||
item.css( 'display', validationFailed ? 'flex' : 'none' );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets UI to core strength meter.
|
||||
*/
|
||||
function restoreCoreStrengthMeter() {
|
||||
renderEmptyState();
|
||||
UIComponents.core.passwordStrengthResults.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an info popover element.
|
||||
*
|
||||
* @param {string} infoText - The text to display in the popover.
|
||||
* @return {jQuery} - The info popover element.
|
||||
*/
|
||||
function createInfoIconPopover( infoText ) {
|
||||
const popover = $( '<div>', { text: infoText, class: 'popover' } ).append(
|
||||
$( '<div>', { class: 'popover-arrow' } )
|
||||
);
|
||||
|
||||
const infoIcon = $( '<span>', { class: 'info-icon' } ).hover(
|
||||
() => popover.fadeIn( 200 ),
|
||||
() => popover.fadeOut( 200 )
|
||||
);
|
||||
|
||||
return $( '<div>', { class: 'info-popover' } ).append( infoIcon, popover );
|
||||
}
|
||||
|
||||
initializeValidationUI();
|
||||
bindEvents();
|
||||
} );
|
||||
@ -5,6 +5,49 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.8.0] - 2026-04-10
|
||||
### Changed
|
||||
- Hide the sidebar upsell when the site is not connected to Jetpack or is in offline mode. [#47967]
|
||||
|
||||
## [0.7.1] - 2026-04-09
|
||||
### Changed
|
||||
- Update package dependencies. [#47890]
|
||||
|
||||
## [0.7.0] - 2026-04-06
|
||||
### Added
|
||||
- Add "Upgrade Jetpack" menu item for free users in the Jetpack admin menu. [#47418]
|
||||
- Admin: Record Tracks when the Jetpack sidebar "Upgrade Jetpack" link is clicked. [#47937]
|
||||
|
||||
### Changed
|
||||
- Update design of the sidebar upsell. [#47909]
|
||||
|
||||
### Fixed
|
||||
- Fix upgrade menu item color on problematic admin color schemes and add build pipeline for CSS assets. [#47903]
|
||||
|
||||
## [0.6.0] - 2026-03-30
|
||||
### Changed
|
||||
- Sidebar: Change "Anti-spam" to "Akismet Anti-spam". [#47834]
|
||||
|
||||
## [0.5.12] - 2026-03-09
|
||||
### Changed
|
||||
- Simplify Akismet admin menu title from 'Akismet Anti-spam' to 'Anti-spam'. [#47417]
|
||||
|
||||
## [0.5.11] - 2025-08-04
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.5.10] - 2025-06-06
|
||||
### Fixed
|
||||
- Fix the Jetpack submenu order for WordPress.com sites that use Nav Unification. [#43781]
|
||||
|
||||
## [0.5.9] - 2025-05-05
|
||||
### Fixed
|
||||
- Remove the Jetpack submenu only if My Jetpack is present. [#43282]
|
||||
|
||||
## [0.5.8] - 2025-04-28
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.5.7] - 2025-03-21
|
||||
### Changed
|
||||
- Internal updates.
|
||||
@ -196,6 +239,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
- Fixing menu visibility issues.
|
||||
|
||||
[0.8.0]: https://github.com/Automattic/jetpack-admin-ui/compare/0.7.1...0.8.0
|
||||
[0.7.1]: https://github.com/Automattic/jetpack-admin-ui/compare/0.7.0...0.7.1
|
||||
[0.7.0]: https://github.com/Automattic/jetpack-admin-ui/compare/0.6.0...0.7.0
|
||||
[0.6.0]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.12...0.6.0
|
||||
[0.5.12]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.11...0.5.12
|
||||
[0.5.11]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.10...0.5.11
|
||||
[0.5.10]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.9...0.5.10
|
||||
[0.5.9]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.8...0.5.9
|
||||
[0.5.8]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.7...0.5.8
|
||||
[0.5.7]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.6...0.5.7
|
||||
[0.5.6]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.5...0.5.6
|
||||
[0.5.5]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.4...0.5.5
|
||||
|
||||
@ -9,24 +9,23 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
<https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
@ -36,48 +35,48 @@ using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
@ -94,7 +93,7 @@ is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
@ -105,29 +104,29 @@ along with the Program.
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
@ -149,26 +148,26 @@ with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
@ -187,7 +186,7 @@ access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
@ -195,7 +194,7 @@ However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
@ -204,7 +203,7 @@ Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
@ -212,7 +211,7 @@ restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
@ -244,7 +243,7 @@ impose that choice.
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
@ -252,7 +251,7 @@ those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
@ -265,7 +264,7 @@ Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
@ -273,9 +272,9 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
@ -285,7 +284,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
@ -295,45 +294,44 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
@ -344,11 +342,11 @@ You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
|
||||
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => '9928b439705112de9a6a');
|
||||
@ -0,0 +1 @@
|
||||
document.addEventListener("DOMContentLoaded",()=>{const e=window.jetpackAdminUiUpgradeMenu;if(void 0===e)return;const t=e.menuItemClass;if(!t)return;const a=document.querySelector(`li.${t} a`);a&&(void 0!==window?.analytics&&e.tracksUserData&&window.analytics.initialize(e.tracksUserData?.userid,e.tracksUserData?.username),a.addEventListener("click",function(){window.analytics?.tracks?.recordEvent("jetpack_sidebar_free_upgrade_click",e.tracksEventData)}))});
|
||||
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => '9d24a8fd2afc23154fc2');
|
||||
@ -0,0 +1 @@
|
||||
:root{--font-title-large:36px;--font-title-small:24px;--font-body:16px;--font-label:12px;--jp-black:#000;--jp-black-80:#2c3338;--jp-white:#fff;--jp-white-off:#f9f9f6;--jp-gray:#dcdcde;--jp-gray-0:#f6f7f7;--jp-gray-5:#dcdcde;--jp-gray-10:#c3c4c7;--jp-gray-20:#a7aaad;--jp-gray-30:#8c8f94;--jp-gray-40:#787c82;--jp-gray-50:#646970;--jp-gray-60:#50575e;--jp-gray-70:#3c434a;--jp-gray-80:#2c3338;--jp-gray-90:#1d2327;--jp-gray-100:#101517;--jp-gray-off:#e2e2df;--jp-yellow-5:#f5e6b3;--jp-yellow-10:#f2cf75;--jp-yellow-40:#c08c00;--jp-orange-20:#faa754;--jp-blue-5:#ced9f2;--jp-red-0:#f7ebec;--jp-red-50:#d63638;--jp-red-60:#b32d2e;--jp-red-80:#8a2424;--jp-red:#d63639;--jp-pink:#c9356e;--jp-green-0:#f0f2eb;--jp-green-5:#d0e6b8;--jp-green-10:#9dd977;--jp-green-20:#64ca43;--jp-green-30:#2fb41f;--jp-green-40:#069e08;--jp-green-50:#008710;--jp-green-60:#007117;--jp-green-70:#005b18;--jp-green-80:#004515;--jp-green-90:#003010;--jp-green-100:#001c09;--jp-green:#069e08;--jp-green-mint:#d3f6d5;--jp-green-primary:var(--jp-green-40);--jp-green-secondary:var(--jp-green-30);--jp-border-radius:4px;--jp-border-radius-rna:8px;--jp-menu-border-height:1px;--jp-underline-thickness:2px;--jp-modal-padding-large:32px;--jp-modal-padding:24px;--jp-modal-padding-small:16px;--jp-modal-radius:8px;--jp-button-padding:8px;--jp-button-radius:4px;--jp-gap:16px;--jp-highlight:#3858e9}#adminmenu li.jetpack-wpadmin-sidebar-free-plan-upsell-menu-item>a,#adminmenu li.jetpack-wpadmin-sidebar-free-plan-upsell-menu-item>a:hover{background:var(--jp-green-40)!important;border-radius:var(--jp-border-radius)!important;box-shadow:none!important;color:var(--jp-white)!important;margin:2px 4px;text-align:center;text-wrap:balance}#adminmenu li.jetpack-wpadmin-sidebar-free-plan-upsell-menu-item>a:hover{background:var(--jp-green-30)!important}
|
||||
@ -0,0 +1 @@
|
||||
:root{--font-title-large:36px;--font-title-small:24px;--font-body:16px;--font-label:12px;--jp-black:#000;--jp-black-80:#2c3338;--jp-white:#fff;--jp-white-off:#f9f9f6;--jp-gray:#dcdcde;--jp-gray-0:#f6f7f7;--jp-gray-5:#dcdcde;--jp-gray-10:#c3c4c7;--jp-gray-20:#a7aaad;--jp-gray-30:#8c8f94;--jp-gray-40:#787c82;--jp-gray-50:#646970;--jp-gray-60:#50575e;--jp-gray-70:#3c434a;--jp-gray-80:#2c3338;--jp-gray-90:#1d2327;--jp-gray-100:#101517;--jp-gray-off:#e2e2df;--jp-yellow-5:#f5e6b3;--jp-yellow-10:#f2cf75;--jp-yellow-40:#c08c00;--jp-orange-20:#faa754;--jp-blue-5:#ced9f2;--jp-red-0:#f7ebec;--jp-red-50:#d63638;--jp-red-60:#b32d2e;--jp-red-80:#8a2424;--jp-red:#d63639;--jp-pink:#c9356e;--jp-green-0:#f0f2eb;--jp-green-5:#d0e6b8;--jp-green-10:#9dd977;--jp-green-20:#64ca43;--jp-green-30:#2fb41f;--jp-green-40:#069e08;--jp-green-50:#008710;--jp-green-60:#007117;--jp-green-70:#005b18;--jp-green-80:#004515;--jp-green-90:#003010;--jp-green-100:#001c09;--jp-green:#069e08;--jp-green-mint:#d3f6d5;--jp-green-primary:var(--jp-green-40);--jp-green-secondary:var(--jp-green-30);--jp-border-radius:4px;--jp-border-radius-rna:8px;--jp-menu-border-height:1px;--jp-underline-thickness:2px;--jp-modal-padding-large:32px;--jp-modal-padding:24px;--jp-modal-padding-small:16px;--jp-modal-radius:8px;--jp-button-padding:8px;--jp-button-radius:4px;--jp-gap:16px;--jp-highlight:#3858e9}#adminmenu li.jetpack-wpadmin-sidebar-free-plan-upsell-menu-item>a,#adminmenu li.jetpack-wpadmin-sidebar-free-plan-upsell-menu-item>a:hover{background:var(--jp-green-40)!important;border-radius:var(--jp-border-radius)!important;box-shadow:none!important;color:var(--jp-white)!important;margin:2px 4px;text-align:center;text-wrap:balance}#adminmenu li.jetpack-wpadmin-sidebar-free-plan-upsell-menu-item>a:hover{background:var(--jp-green-30)!important}
|
||||
@ -4,14 +4,16 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
"php": ">=7.2",
|
||||
"automattic/jetpack-redirect": "^3.0.9",
|
||||
"automattic/jetpack-status": "^6.1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "^3.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.2",
|
||||
"automattic/jetpack-logo": "^3.0.4",
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.14",
|
||||
"automattic/jetpack-logo": "^3.0.5",
|
||||
"automattic/jetpack-test-environment": "@dev",
|
||||
"automattic/phpunit-select-config": "^1.0.1"
|
||||
"automattic/phpunit-select-config": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
@ -22,6 +24,12 @@
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"build-development": [
|
||||
"pnpm run build"
|
||||
],
|
||||
"build-production": [
|
||||
"pnpm run build-production"
|
||||
],
|
||||
"phpunit": [
|
||||
"phpunit-select-config phpunit.#.xml.dist --colors=always"
|
||||
],
|
||||
@ -30,6 +38,10 @@
|
||||
],
|
||||
"test-php": [
|
||||
"@composer phpunit"
|
||||
],
|
||||
"watch": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"pnpm run watch"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
@ -42,7 +54,12 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-admin-ui/compare/${old}...${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "0.5.x-dev"
|
||||
"dev-trunk": "0.8.x-dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"test-only": [
|
||||
"packages/connection"
|
||||
]
|
||||
},
|
||||
"version-constants": {
|
||||
"::PACKAGE_VERSION": "src/class-admin-menu.php"
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Marks the wp-admin Jetpack sidebar "Upgrade Jetpack" item for Tracks.
|
||||
*/
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
const config = window.jetpackAdminUiUpgradeMenu;
|
||||
if ( typeof config === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const className = config.menuItemClass;
|
||||
if ( ! className ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Class comes from PHP (UPGRADE_MENU_SLUG); safe for querySelector.
|
||||
const item = document.querySelector( `li.${ className } a` );
|
||||
if ( ! item ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize Tracks
|
||||
if ( 'undefined' !== typeof window?.analytics && config.tracksUserData ) {
|
||||
window.analytics.initialize( config.tracksUserData?.userid, config.tracksUserData?.username );
|
||||
}
|
||||
|
||||
item.addEventListener( 'click', function () {
|
||||
window.analytics?.tracks?.recordEvent(
|
||||
'jetpack_sidebar_free_upgrade_click',
|
||||
config.tracksEventData
|
||||
);
|
||||
} );
|
||||
} );
|
||||
@ -7,13 +7,33 @@
|
||||
|
||||
namespace Automattic\Jetpack\Admin_UI;
|
||||
|
||||
use Automattic\Jetpack\Tracking;
|
||||
use Jetpack_Options;
|
||||
use Jetpack_Tracks_Client;
|
||||
|
||||
/**
|
||||
* This class offers a wrapper to add_submenu_page and makes sure stand-alone plugin's menu items are always added under the Jetpack top level menu.
|
||||
* If the Jetpack top level was not previously registered by other plugin, it will be registered here.
|
||||
*/
|
||||
class Admin_Menu {
|
||||
|
||||
const PACKAGE_VERSION = '0.5.7';
|
||||
const PACKAGE_VERSION = '0.8.0';
|
||||
|
||||
/**
|
||||
* Slug used for the upgrade menu item and redirect URL.
|
||||
*
|
||||
* Keep the slug in sync with `$upgrade-menu-slug` at admin-ui-upgrade-menu.scss
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const UPGRADE_MENU_SLUG = 'jetpack-wpadmin-sidebar-free-plan-upsell-menu-item';
|
||||
|
||||
/**
|
||||
* Fallback upgrade URL when the Redirect class is unavailable.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const UPGRADE_MENU_FALLBACK_URL = 'https://jetpack.com/upgrade/';
|
||||
|
||||
/**
|
||||
* Whether this class has been initialized
|
||||
@ -29,6 +49,13 @@ class Admin_Menu {
|
||||
*/
|
||||
private static $menu_items = array();
|
||||
|
||||
/**
|
||||
* Optional connection manager dependency.
|
||||
*
|
||||
* @var object|null
|
||||
*/
|
||||
private static $connection_manager = null;
|
||||
|
||||
/**
|
||||
* Initialize the class and set up the main hook
|
||||
*
|
||||
@ -40,6 +67,7 @@ class Admin_Menu {
|
||||
self::handle_akismet_menu();
|
||||
add_action( 'admin_menu', array( __CLASS__, 'admin_menu_hook_callback' ), 1000 ); // Jetpack uses 998.
|
||||
add_action( 'network_admin_menu', array( __CLASS__, 'admin_menu_hook_callback' ), 1000 ); // Jetpack uses 998.
|
||||
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'add_upgrade_menu_item_styles' ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,6 +168,8 @@ class Admin_Menu {
|
||||
if ( ! $can_see_toplevel_menu ) {
|
||||
remove_menu_page( 'jetpack' );
|
||||
}
|
||||
|
||||
self::maybe_add_upgrade_menu_item();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,15 +179,15 @@ class Admin_Menu {
|
||||
* aggreagate all menu items registered by stand-alone plugins and make sure they all go under the same
|
||||
* Jetpack top level menu. It will also handle the top level menu registration in case the Jetpack plugin is not present.
|
||||
*
|
||||
* @param string $page_title The text to be displayed in the title tags of the page when the menu
|
||||
* is selected.
|
||||
* @param string $menu_title The text to be used for the menu.
|
||||
* @param string $capability The capability required for this menu to be displayed to the user.
|
||||
* @param string $menu_slug The slug name to refer to this menu by. Should be unique for this menu
|
||||
* and only include lowercase alphanumeric, dashes, and underscores characters
|
||||
* to be compatible with sanitize_key().
|
||||
* @param callable $function The function to be called to output the content for this page.
|
||||
* @param int $position The position in the menu order this item should appear. Leave empty typically.
|
||||
* @param string $page_title The text to be displayed in the title tags of the page when the menu
|
||||
* is selected.
|
||||
* @param string $menu_title The text to be used for the menu.
|
||||
* @param string $capability The capability required for this menu to be displayed to the user.
|
||||
* @param string $menu_slug The slug name to refer to this menu by. Should be unique for this menu
|
||||
* and only include lowercase alphanumeric, dashes, and underscores characters
|
||||
* to be compatible with sanitize_key().
|
||||
* @param callable|null $function The function to be called to output the content for this page.
|
||||
* @param int $position The position in the menu order this item should appear. Leave empty typically.
|
||||
*
|
||||
* @return string The resulting page's hook_suffix
|
||||
*/
|
||||
@ -225,4 +255,219 @@ class Admin_Menu {
|
||||
$url = $fallback ? $fallback : admin_url();
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current site should show the upgrade menu item.
|
||||
*
|
||||
* The upgrade menu is only shown to administrators on free-plan sites
|
||||
* that are not hosted on WordPress.com.
|
||||
*
|
||||
* @return bool True if the upgrade menu should be shown.
|
||||
*/
|
||||
private static function should_show_upgrade_menu() {
|
||||
|
||||
// Only show to administrators.
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't show upsells on WordPress.com platform.
|
||||
if ( class_exists( '\Automattic\Jetpack\Status\Host' ) ) {
|
||||
$host = new \Automattic\Jetpack\Status\Host();
|
||||
if ( $host->is_wpcom_platform() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't show upsells in offline/development mode.
|
||||
if ( class_exists( '\Automattic\Jetpack\Status' ) ) {
|
||||
$status = new \Automattic\Jetpack\Status();
|
||||
if ( $status->is_offline_mode() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only show after the site and current user are connected.
|
||||
if ( ! self::is_site_and_user_connected() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only show to free-plan sites.
|
||||
return self::is_free_plan();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the site and current user are connected to WordPress.com.
|
||||
*
|
||||
* @return bool True if site and current user are connected.
|
||||
*/
|
||||
private static function is_site_and_user_connected() {
|
||||
$connection_manager = self::$connection_manager;
|
||||
if ( ! $connection_manager && class_exists( '\Automattic\Jetpack\Connection\Manager' ) ) {
|
||||
$connection_manager = new \Automattic\Jetpack\Connection\Manager();
|
||||
self::$connection_manager = $connection_manager;
|
||||
}
|
||||
|
||||
if (
|
||||
$connection_manager
|
||||
&& is_callable( array( $connection_manager, 'is_connected' ) )
|
||||
&& is_callable( array( $connection_manager, 'is_user_connected' ) )
|
||||
) {
|
||||
return (bool) $connection_manager->is_connected()
|
||||
&& (bool) $connection_manager->is_user_connected( get_current_user_id() );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection manager dependency; used by tests.
|
||||
*
|
||||
* @param object|null $connection_manager Connection manager object.
|
||||
* @return void
|
||||
*/
|
||||
public static function set_connection_manager( $connection_manager ) {
|
||||
self::$connection_manager = $connection_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current site is on a free Jetpack plan with no active paid license.
|
||||
*
|
||||
* @return bool True if the site has no paid plan.
|
||||
*/
|
||||
private static function is_free_plan() {
|
||||
// Check the active plan - use the is_free field or product_slug.
|
||||
$plan = get_option( 'jetpack_active_plan', array() );
|
||||
|
||||
// Back-compat: older plan payloads use class to indicate paid plans.
|
||||
if ( isset( $plan['class'] ) && 'free' !== $plan['class'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the plan explicitly says it's not free, trust that.
|
||||
if ( isset( $plan['is_free'] ) && false === $plan['is_free'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the product slug indicates a paid plan.
|
||||
if ( isset( $plan['product_slug'] ) && 'jetpack_free' !== $plan['product_slug'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Also check for site products (licenses can add products without changing plan).
|
||||
$products = get_option( 'jetpack_site_products', array() );
|
||||
if ( ! empty( $products ) && is_array( $products ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally adds an "Upgrade Jetpack" submenu item for free-plan sites.
|
||||
*
|
||||
* Only shown to users with manage_options capability on self-hosted sites without a paid Jetpack plan or license.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function maybe_add_upgrade_menu_item() {
|
||||
if ( ! self::should_show_upgrade_menu() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$upgrade_url = class_exists( '\Automattic\Jetpack\Redirect' )
|
||||
? \Automattic\Jetpack\Redirect::get_url( self::UPGRADE_MENU_SLUG )
|
||||
: self::UPGRADE_MENU_FALLBACK_URL;
|
||||
|
||||
$menu_title = esc_html__( 'Upgrade Jetpack', 'jetpack-admin-ui' );
|
||||
|
||||
add_submenu_page(
|
||||
'jetpack',
|
||||
$menu_title,
|
||||
$menu_title,
|
||||
'manage_options',
|
||||
esc_url( $upgrade_url ),
|
||||
null, // @phan-suppress-current-line PhanTypeMismatchArgumentProbablyReal -- Core should ideally document null for no-callback arg. https://core.trac.wordpress.org/ticket/52539.
|
||||
999
|
||||
);
|
||||
|
||||
// Add a CSS class to the <li> element so styles can target it precisely.
|
||||
global $submenu;
|
||||
if ( ! empty( $submenu['jetpack'] ) ) {
|
||||
foreach ( $submenu['jetpack'] as $index => $item ) {
|
||||
if ( isset( $item[2] ) && false !== strpos( $item[2], self::UPGRADE_MENU_SLUG ) ) {
|
||||
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
$submenu['jetpack'][ $index ][4] = ( ! empty( $item[4] ) ? $item[4] . ' ' : '' ) . self::UPGRADE_MENU_SLUG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues admin styles for the "Upgrade Jetpack" menu item.
|
||||
*
|
||||
* The sidebar menu is visible on every admin page, so styles load globally.
|
||||
* Only enqueues for free-plan sites on self-hosted installs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function add_upgrade_menu_item_styles() {
|
||||
if ( ! self::should_show_upgrade_menu() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$asset_file = dirname( __DIR__ ) . '/build/admin-ui-upgrade-menu.asset.php';
|
||||
$asset = file_exists( $asset_file ) ? require $asset_file : array();
|
||||
|
||||
wp_enqueue_style(
|
||||
'jetpack-admin-ui-upgrade-menu',
|
||||
plugins_url( '../build/admin-ui-upgrade-menu.css', __FILE__ ),
|
||||
$asset['dependencies'] ?? array(),
|
||||
$asset['version'] ?? self::PACKAGE_VERSION
|
||||
);
|
||||
|
||||
self::enqueue_upgrade_menu_tracks_script( $asset );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues Tracks for the upgrade submenu item.
|
||||
*
|
||||
* @param array $asset Parsed contents of admin-ui-upgrade-menu.asset.php.
|
||||
* @return void
|
||||
*/
|
||||
private static function enqueue_upgrade_menu_tracks_script( $asset ) {
|
||||
if ( ! class_exists( '\Automattic\Jetpack\Tracking' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tracking::register_tracks_functions_scripts( true );
|
||||
|
||||
wp_enqueue_script(
|
||||
'jetpack-admin-ui-upgrade-menu-tracking',
|
||||
plugins_url( '../build/admin-ui-upgrade-menu-tracking.js', __FILE__ ),
|
||||
$asset['dependencies'] ?? array(),
|
||||
$asset['version'] ?? self::PACKAGE_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
$current_screen = get_current_screen();
|
||||
$is_admin = current_user_can( 'jetpack_disconnect' );
|
||||
$site_id = class_exists( 'Jetpack_Options' ) ? Jetpack_Options::get_option( 'id' ) : null;
|
||||
$tracks_user_data = class_exists( 'Jetpack_Tracks_Client' ) ? Jetpack_Tracks_Client::get_connected_user_tracks_identity() : null;
|
||||
|
||||
wp_localize_script(
|
||||
'jetpack-admin-ui-upgrade-menu-tracking',
|
||||
'jetpackAdminUiUpgradeMenu',
|
||||
array(
|
||||
'menuItemClass' => self::UPGRADE_MENU_SLUG,
|
||||
'tracksUserData' => $tracks_user_data,
|
||||
'tracksEventData' => array(
|
||||
'is_admin' => $is_admin,
|
||||
'current_screen' => $current_screen ? $current_screen->id : false,
|
||||
'blog_id' => $site_id,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,230 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [4.3.32] - 2026-04-09
|
||||
### Changed
|
||||
- Update package dependencies. [#47890]
|
||||
|
||||
## [4.3.31] - 2026-04-06
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.3.30] - 2026-03-30
|
||||
### Changed
|
||||
- Update package dependencies. [#47799]
|
||||
|
||||
## [4.3.29] - 2026-03-23
|
||||
### Changed
|
||||
- Update package dependencies. [#47684]
|
||||
|
||||
## [4.3.28] - 2026-03-16
|
||||
### Changed
|
||||
- Update dependencies. [#47472]
|
||||
|
||||
## [4.3.27] - 2026-03-09
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.3.26] - 2026-02-26
|
||||
### Changed
|
||||
- Update package dependencies. [#47300]
|
||||
|
||||
## [4.3.25] - 2026-02-18
|
||||
### Changed
|
||||
- Update package dependencies. [#47173]
|
||||
|
||||
## [4.3.24] - 2026-02-16
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [4.3.23] - 2026-02-10
|
||||
### Changed
|
||||
- Update package dependencies. [#47002]
|
||||
|
||||
## [4.3.22] - 2026-02-02
|
||||
### Changed
|
||||
- Update package dependencies. [#46836] [#46854]
|
||||
|
||||
## [4.3.21] - 2026-01-26
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.3.20] - 2026-01-19
|
||||
### Changed
|
||||
- Update package dependencies. [#46647]
|
||||
|
||||
## [4.3.19] - 2026-01-07
|
||||
### Changed
|
||||
- Update package dependencies. [#46456]
|
||||
|
||||
## [4.3.18] - 2025-12-22
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [4.3.17] - 2025-12-15
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [4.3.16] - 2025-12-11
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.3.15] - 2025-12-08
|
||||
### Fixed
|
||||
- Ensure proper flags are used with `json_encode()`. [#46092]
|
||||
|
||||
## [4.3.14] - 2025-12-01
|
||||
### Changed
|
||||
- Update package dependencies. [#46143]
|
||||
|
||||
## [4.3.13] - 2025-11-17
|
||||
### Changed
|
||||
- Update package dependencies. [#45915] [#45958]
|
||||
|
||||
## [4.3.12] - 2025-11-10
|
||||
### Changed
|
||||
- Tests: Ensure PHP 8.5 compatibility. [#45769]
|
||||
- Update package dependencies. [#45756]
|
||||
|
||||
### Fixed
|
||||
- Tests: Improve compatibility with PHP 8.5. [#45771]
|
||||
|
||||
## [4.3.11] - 2025-10-28
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.3.10] - 2025-10-02
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.3.9] - 2025-09-22
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.3.8] - 2025-09-19
|
||||
### Changed
|
||||
- Update package dependencies. [#45173] [#45229]
|
||||
|
||||
## [4.3.7] - 2025-09-15
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [4.3.6] - 2025-09-08
|
||||
### Changed
|
||||
- Update package dependencies. [#45027]
|
||||
|
||||
## [4.3.5] - 2025-08-18
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.3.4] - 2025-08-13
|
||||
### Changed
|
||||
- Update package dependencies. [#44701] [#44725]
|
||||
|
||||
## [4.3.3] - 2025-08-11
|
||||
### Changed
|
||||
- Update package dependencies. [#44677]
|
||||
|
||||
## [4.3.2] - 2025-08-04
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [4.3.1] - 2025-07-30
|
||||
### Fixed
|
||||
- Script Data: Ensure we always enqueue instead of print script data. [#44447]
|
||||
|
||||
## [4.3.0] - 2025-07-23
|
||||
### Changed
|
||||
- Script data: Provide script data to authenticated REST API requests. [#44077]
|
||||
|
||||
## [4.2.0] - 2025-07-21
|
||||
### Changed
|
||||
- Script Data: Ensure we only add host information on the front-end for P2 and sites using Verbum Comments. [#44241]
|
||||
|
||||
## [4.1.2] - 2025-07-08
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.1.1] - 2025-07-08
|
||||
### Changed
|
||||
- Update package dependencies. [#44217]
|
||||
|
||||
## [4.1.0] - 2025-07-07
|
||||
### Changed
|
||||
- Scripts: Ensure host-related checks and functionality are only added via Assets. [#44133]
|
||||
|
||||
## [4.0.32] - 2025-07-03
|
||||
### Changed
|
||||
- Update package dependencies. [#44148]
|
||||
|
||||
## [4.0.31] - 2025-06-30
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.0.30] - 2025-06-27
|
||||
### Added
|
||||
- Script Data: Add host information available on front-end. [#44072]
|
||||
|
||||
## [4.0.29] - 2025-06-24
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.0.28] - 2025-06-23
|
||||
### Changed
|
||||
- Update package dependencies. [#44020]
|
||||
|
||||
## [4.0.27] - 2025-06-18
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [4.0.26] - 2025-06-10
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.0.25] - 2025-06-04
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.0.24] - 2025-06-03
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [4.0.23] - 2025-06-02
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.0.22] - 2025-05-26
|
||||
### Changed
|
||||
- Update package dependencies. [#43578]
|
||||
|
||||
## [4.0.21] - 2025-05-22
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.0.20] - 2025-05-05
|
||||
### Changed
|
||||
- Update package dependencies. [#43326]
|
||||
|
||||
## [4.0.19] - 2025-04-28
|
||||
### Fixed
|
||||
- Newsletters: Show newsletter widget on P2s. [#43085]
|
||||
|
||||
## [4.0.18] - 2025-04-14
|
||||
### Fixed
|
||||
- Linting: Clean up various Stylelint violations. [#43010]
|
||||
|
||||
## [4.0.17] - 2025-04-01
|
||||
### Changed
|
||||
- Update package dependencies. [#42809]
|
||||
|
||||
## [4.0.16] - 2025-04-01
|
||||
### Changed
|
||||
- Update dependencies. [#42554]
|
||||
|
||||
## [4.0.15] - 2025-03-31
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [4.0.14] - 2025-03-21
|
||||
### Changed
|
||||
- Internal updates.
|
||||
@ -592,6 +816,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Statically access asset tools
|
||||
|
||||
[4.3.32]: https://github.com/Automattic/jetpack-assets/compare/v4.3.31...v4.3.32
|
||||
[4.3.31]: https://github.com/Automattic/jetpack-assets/compare/v4.3.30...v4.3.31
|
||||
[4.3.30]: https://github.com/Automattic/jetpack-assets/compare/v4.3.29...v4.3.30
|
||||
[4.3.29]: https://github.com/Automattic/jetpack-assets/compare/v4.3.28...v4.3.29
|
||||
[4.3.28]: https://github.com/Automattic/jetpack-assets/compare/v4.3.27...v4.3.28
|
||||
[4.3.27]: https://github.com/Automattic/jetpack-assets/compare/v4.3.26...v4.3.27
|
||||
[4.3.26]: https://github.com/Automattic/jetpack-assets/compare/v4.3.25...v4.3.26
|
||||
[4.3.25]: https://github.com/Automattic/jetpack-assets/compare/v4.3.24...v4.3.25
|
||||
[4.3.24]: https://github.com/Automattic/jetpack-assets/compare/v4.3.23...v4.3.24
|
||||
[4.3.23]: https://github.com/Automattic/jetpack-assets/compare/v4.3.22...v4.3.23
|
||||
[4.3.22]: https://github.com/Automattic/jetpack-assets/compare/v4.3.21...v4.3.22
|
||||
[4.3.21]: https://github.com/Automattic/jetpack-assets/compare/v4.3.20...v4.3.21
|
||||
[4.3.20]: https://github.com/Automattic/jetpack-assets/compare/v4.3.19...v4.3.20
|
||||
[4.3.19]: https://github.com/Automattic/jetpack-assets/compare/v4.3.18...v4.3.19
|
||||
[4.3.18]: https://github.com/Automattic/jetpack-assets/compare/v4.3.17...v4.3.18
|
||||
[4.3.17]: https://github.com/Automattic/jetpack-assets/compare/v4.3.16...v4.3.17
|
||||
[4.3.16]: https://github.com/Automattic/jetpack-assets/compare/v4.3.15...v4.3.16
|
||||
[4.3.15]: https://github.com/Automattic/jetpack-assets/compare/v4.3.14...v4.3.15
|
||||
[4.3.14]: https://github.com/Automattic/jetpack-assets/compare/v4.3.13...v4.3.14
|
||||
[4.3.13]: https://github.com/Automattic/jetpack-assets/compare/v4.3.12...v4.3.13
|
||||
[4.3.12]: https://github.com/Automattic/jetpack-assets/compare/v4.3.11...v4.3.12
|
||||
[4.3.11]: https://github.com/Automattic/jetpack-assets/compare/v4.3.10...v4.3.11
|
||||
[4.3.10]: https://github.com/Automattic/jetpack-assets/compare/v4.3.9...v4.3.10
|
||||
[4.3.9]: https://github.com/Automattic/jetpack-assets/compare/v4.3.8...v4.3.9
|
||||
[4.3.8]: https://github.com/Automattic/jetpack-assets/compare/v4.3.7...v4.3.8
|
||||
[4.3.7]: https://github.com/Automattic/jetpack-assets/compare/v4.3.6...v4.3.7
|
||||
[4.3.6]: https://github.com/Automattic/jetpack-assets/compare/v4.3.5...v4.3.6
|
||||
[4.3.5]: https://github.com/Automattic/jetpack-assets/compare/v4.3.4...v4.3.5
|
||||
[4.3.4]: https://github.com/Automattic/jetpack-assets/compare/v4.3.3...v4.3.4
|
||||
[4.3.3]: https://github.com/Automattic/jetpack-assets/compare/v4.3.2...v4.3.3
|
||||
[4.3.2]: https://github.com/Automattic/jetpack-assets/compare/v4.3.1...v4.3.2
|
||||
[4.3.1]: https://github.com/Automattic/jetpack-assets/compare/v4.3.0...v4.3.1
|
||||
[4.3.0]: https://github.com/Automattic/jetpack-assets/compare/v4.2.0...v4.3.0
|
||||
[4.2.0]: https://github.com/Automattic/jetpack-assets/compare/v4.1.2...v4.2.0
|
||||
[4.1.2]: https://github.com/Automattic/jetpack-assets/compare/v4.1.1...v4.1.2
|
||||
[4.1.1]: https://github.com/Automattic/jetpack-assets/compare/v4.1.0...v4.1.1
|
||||
[4.1.0]: https://github.com/Automattic/jetpack-assets/compare/v4.0.32...v4.1.0
|
||||
[4.0.32]: https://github.com/Automattic/jetpack-assets/compare/v4.0.31...v4.0.32
|
||||
[4.0.31]: https://github.com/Automattic/jetpack-assets/compare/v4.0.30...v4.0.31
|
||||
[4.0.30]: https://github.com/Automattic/jetpack-assets/compare/v4.0.29...v4.0.30
|
||||
[4.0.29]: https://github.com/Automattic/jetpack-assets/compare/v4.0.28...v4.0.29
|
||||
[4.0.28]: https://github.com/Automattic/jetpack-assets/compare/v4.0.27...v4.0.28
|
||||
[4.0.27]: https://github.com/Automattic/jetpack-assets/compare/v4.0.26...v4.0.27
|
||||
[4.0.26]: https://github.com/Automattic/jetpack-assets/compare/v4.0.25...v4.0.26
|
||||
[4.0.25]: https://github.com/Automattic/jetpack-assets/compare/v4.0.24...v4.0.25
|
||||
[4.0.24]: https://github.com/Automattic/jetpack-assets/compare/v4.0.23...v4.0.24
|
||||
[4.0.23]: https://github.com/Automattic/jetpack-assets/compare/v4.0.22...v4.0.23
|
||||
[4.0.22]: https://github.com/Automattic/jetpack-assets/compare/v4.0.21...v4.0.22
|
||||
[4.0.21]: https://github.com/Automattic/jetpack-assets/compare/v4.0.20...v4.0.21
|
||||
[4.0.20]: https://github.com/Automattic/jetpack-assets/compare/v4.0.19...v4.0.20
|
||||
[4.0.19]: https://github.com/Automattic/jetpack-assets/compare/v4.0.18...v4.0.19
|
||||
[4.0.18]: https://github.com/Automattic/jetpack-assets/compare/v4.0.17...v4.0.18
|
||||
[4.0.17]: https://github.com/Automattic/jetpack-assets/compare/v4.0.16...v4.0.17
|
||||
[4.0.16]: https://github.com/Automattic/jetpack-assets/compare/v4.0.15...v4.0.16
|
||||
[4.0.15]: https://github.com/Automattic/jetpack-assets/compare/v4.0.14...v4.0.15
|
||||
[4.0.14]: https://github.com/Automattic/jetpack-assets/compare/v4.0.13...v4.0.14
|
||||
[4.0.13]: https://github.com/Automattic/jetpack-assets/compare/v4.0.12...v4.0.13
|
||||
[4.0.12]: https://github.com/Automattic/jetpack-assets/compare/v4.0.11...v4.0.12
|
||||
|
||||
@ -9,24 +9,23 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
<https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
@ -36,48 +35,48 @@ using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
@ -94,7 +93,7 @@ is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
@ -105,29 +104,29 @@ along with the Program.
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
@ -149,26 +148,26 @@ with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
@ -187,7 +186,7 @@ access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
@ -195,7 +194,7 @@ However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
@ -204,7 +203,7 @@ Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
@ -212,7 +211,7 @@ restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
@ -244,7 +243,7 @@ impose that choice.
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
@ -252,7 +251,7 @@ those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
@ -265,7 +264,7 @@ Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
@ -273,9 +272,9 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
@ -285,7 +284,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
@ -295,45 +294,44 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
@ -344,11 +342,11 @@ You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
|
||||
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('wp-i18n'), 'version' => 'becd7d9884bc1b331e45');
|
||||
<?php return array('dependencies' => array('wp-i18n'), 'version' => '5ba5dddc04be2306aaf0');
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => '7f1c9fc474dccfef702f');
|
||||
<?php return array('dependencies' => array(), 'version' => '063e99e8f3d8166cfb17');
|
||||
|
||||
@ -1 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.JetpackScriptDataModule=t():e.JetpackScriptDataModule=t()}(globalThis,(()=>(()=>{"use strict";var e={729:(e,t,r)=>{r.d(t,{$8:()=>n.$8,IT:()=>n.IT,L2:()=>n.L2,Sy:()=>n.Sy,au:()=>n.au,d9:()=>n.d9,d_:()=>n.d_,e5:()=>n.e5,hT:()=>n.hT,lI:()=>n.lI,mH:()=>n.mH,oQ:()=>n.oQ,sV:()=>n.sV});var n=r(336)},336:(e,t,r)=>{function n(){return window.JetpackScriptData}function o(){return n().site}function i(e=""){return`${n().site.admin_url}${e}`}function u(e=""){return i(`admin.php?page=jetpack${e}`)}function a(e=""){return i(`admin.php?page=my-jetpack${e}`)}function c(){return n().site.plan?.features?.active??[]}function s(e){return c().includes(e)}function p(){return"wpcom"===n().site?.host}function d(){return"atomic"===n().site?.host}function f(){return"woa"===n().site?.host}function l(){return p()||f()}function m(){return"unknown"===n()?.site?.host}function S(e){return n().user.current_user.capabilities[e]}r.d(t,{$8:()=>l,IT:()=>s,L2:()=>m,Sy:()=>p,au:()=>n,d9:()=>d,d_:()=>S,e5:()=>a,hT:()=>i,lI:()=>f,mH:()=>c,oQ:()=>u,sV:()=>o})}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,r),i.exports}r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};r.r(n),r.d(n,{currentUserCan:()=>o.d_,getActiveFeatures:()=>o.mH,getAdminUrl:()=>o.hT,getJetpackAdminPageUrl:()=>o.oQ,getMyJetpackUrl:()=>o.e5,getScriptData:()=>o.au,getSiteData:()=>o.sV,isAtomicSite:()=>o.d9,isJetpackSelfHostedSite:()=>o.L2,isSimpleSite:()=>o.Sy,isWoASite:()=>o.lI,isWpcomPlatformSite:()=>o.$8,siteHasFeature:()=>o.IT});var o=r(729);return n})()));
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.JetpackScriptDataModule=t():e.JetpackScriptDataModule=t()}(globalThis,()=>(()=>{"use strict";var e={729(e,t,r){r.d(t,{$8:()=>n.$8,IT:()=>n.IT,KS:()=>n.KS,L2:()=>n.L2,Sy:()=>n.Sy,au:()=>n.au,d_:()=>n.d_,e5:()=>n.e5,hT:()=>n.hT,lI:()=>n.lI,mH:()=>n.mH,oQ:()=>n.oQ,sV:()=>n.sV});var n=r(336)},336(e,t,r){function n(){return window.JetpackScriptData}function o(){return n()?.site}function i(e=""){return`${n()?.site.admin_url}${e}`}function a(e=""){return i(`admin.php?page=jetpack${e}`)}function u(e=""){return i(`admin.php?page=my-jetpack${e}`)}function p(){return n()?.site.plan?.features?.active??[]}function c(e){return-1!==p().indexOf(e)}function s(){return"wpcom"===n()?.site?.host}function f(){return"woa"===n()?.site?.host}function d(){return n()?.site?.is_wpcom_platform}function l(){return"unknown"===n()?.site?.host}function S(){return s()?"simple":f()?"woa":"jetpack"}function m(e){return n()?.user.current_user.capabilities[e]}r.d(t,{$8:()=>d,IT:()=>c,KS:()=>S,L2:()=>l,Sy:()=>s,au:()=>n,d_:()=>m,e5:()=>u,hT:()=>i,lI:()=>f,mH:()=>p,oQ:()=>a,sV:()=>o})}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,r),i.exports}r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};r.r(n),r.d(n,{currentUserCan:()=>o.d_,getActiveFeatures:()=>o.mH,getAdminUrl:()=>o.hT,getJetpackAdminPageUrl:()=>o.oQ,getMyJetpackUrl:()=>o.e5,getScriptData:()=>o.au,getSiteData:()=>o.sV,getSiteType:()=>o.KS,isJetpackSelfHostedSite:()=>o.L2,isSimpleSite:()=>o.Sy,isWoASite:()=>o.lI,isWpcomPlatformSite:()=>o.$8,siteHasFeature:()=>o.IT});var o=r(729);return n})());
|
||||
@ -5,14 +5,15 @@
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"automattic/jetpack-constants": "^3.0.5"
|
||||
"automattic/jetpack-constants": "^3.0.8",
|
||||
"automattic/jetpack-status": "^6.1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"brain/monkey": "^2.6.2",
|
||||
"yoast/phpunit-polyfills": "^3.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.2",
|
||||
"wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0",
|
||||
"automattic/phpunit-select-config": "^1.0.1"
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.14",
|
||||
"wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
|
||||
"automattic/phpunit-select-config": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
@ -53,7 +54,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-assets/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "4.0.x-dev"
|
||||
"dev-trunk": "4.3.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,7 +530,7 @@ class Assets {
|
||||
} else {
|
||||
$data['domainMap'] = (object) $data['domainMap']; // Ensure it becomes a json object.
|
||||
$data['domainPaths'] = (object) $data['domainPaths']; // Ensure it becomes a json object.
|
||||
$wp_scripts->add_inline_script( $handle, 'wp.jpI18nLoader.state = ' . wp_json_encode( $data, JSON_UNESCAPED_SLASHES ) . ';' );
|
||||
$wp_scripts->add_inline_script( $handle, 'wp.jpI18nLoader.state = ' . wp_json_encode( $data, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';' );
|
||||
}
|
||||
|
||||
// Deprecated state module: Depend on wp-i18n to ensure global `wp` exists and because anything needing this will need that too.
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
namespace Automattic\Jetpack\Assets;
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
use Automattic\Jetpack\Status;
|
||||
use Automattic\Jetpack\Status\Host;
|
||||
|
||||
/**
|
||||
* Class script data
|
||||
@ -83,18 +85,32 @@ class Script_Data {
|
||||
|
||||
self::$did_render_script_data = true;
|
||||
|
||||
$script_data = is_admin() ? self::get_admin_script_data() : self::get_public_script_data();
|
||||
$script_data = is_admin() || self::is_authenticated_rest_request()
|
||||
? self::get_admin_script_data()
|
||||
: self::get_public_script_data();
|
||||
|
||||
$script_data = wp_json_encode(
|
||||
$script_data,
|
||||
JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE
|
||||
);
|
||||
if ( ! empty( $script_data ) ) {
|
||||
$script_data = wp_json_encode(
|
||||
$script_data,
|
||||
JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE
|
||||
);
|
||||
|
||||
wp_add_inline_script(
|
||||
self::SCRIPT_HANDLE,
|
||||
sprintf( 'window.JetpackScriptData = %s;', $script_data ),
|
||||
'before'
|
||||
);
|
||||
wp_add_inline_script(
|
||||
self::SCRIPT_HANDLE,
|
||||
sprintf( 'window.JetpackScriptData = %s;', $script_data ),
|
||||
'before'
|
||||
);
|
||||
Assets::enqueue_script( self::SCRIPT_HANDLE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current request is an authenticated REST API request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function is_authenticated_rest_request() {
|
||||
return wp_is_serving_rest_request() && current_user_can( 'read' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,20 +124,23 @@ class Script_Data {
|
||||
|
||||
$data = array(
|
||||
'site' => array(
|
||||
'admin_url' => esc_url_raw( admin_url() ),
|
||||
'date_format' => get_option( 'date_format' ),
|
||||
'icon' => self::get_site_icon(),
|
||||
'is_multisite' => is_multisite(),
|
||||
'plan' => array(
|
||||
'admin_url' => esc_url_raw( admin_url() ),
|
||||
'date_format' => get_option( 'date_format' ),
|
||||
'icon' => self::get_site_icon(),
|
||||
'is_multisite' => is_multisite(),
|
||||
'host' => ( new Host() )->get_known_host_guess(),
|
||||
'is_wpcom_platform' => ( new Host() )->is_wpcom_platform(),
|
||||
'plan' => array(
|
||||
// The properties here should be updated by the consumer package/plugin.
|
||||
// It includes properties like 'product_slug', 'features', etc.
|
||||
'product_slug' => '',
|
||||
),
|
||||
'rest_nonce' => wp_create_nonce( 'wp_rest' ),
|
||||
'rest_root' => esc_url_raw( rest_url() ),
|
||||
'title' => self::get_site_title(),
|
||||
'wp_version' => $wp_version,
|
||||
'wpcom' => array(
|
||||
'rest_nonce' => wp_create_nonce( 'wp_rest' ),
|
||||
'rest_root' => esc_url_raw( rest_url() ),
|
||||
'suffix' => ( new Status() )->get_site_suffix(),
|
||||
'title' => self::get_site_title(),
|
||||
'wp_version' => $wp_version,
|
||||
'wpcom' => array(
|
||||
// This should contain the connected site details like blog_id, is_atomic etc.
|
||||
'blog_id' => 0,
|
||||
),
|
||||
@ -147,18 +166,13 @@ class Script_Data {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the admin script data.
|
||||
* Get the public script data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function get_public_script_data() {
|
||||
|
||||
$data = array(
|
||||
'site' => array(
|
||||
'icon' => self::get_site_icon(),
|
||||
'title' => self::get_site_title(),
|
||||
),
|
||||
);
|
||||
$data = array();
|
||||
|
||||
/**
|
||||
* Filter the public script data.
|
||||
|
||||
@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.3.8] - 2025-09-08
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.3.7] - 2025-04-28
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.3.6] - 2025-03-24
|
||||
### Changed
|
||||
- Internal updates.
|
||||
@ -76,6 +84,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
- Initial release (improved helper script installer logging). [#34297]
|
||||
|
||||
[0.3.8]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.7...v0.3.8
|
||||
[0.3.7]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.6...v0.3.7
|
||||
[0.3.6]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.5...v0.3.6
|
||||
[0.3.5]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.4...v0.3.5
|
||||
[0.3.4]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.3...v0.3.4
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "^3.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.2",
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.6",
|
||||
"automattic/jetpack-test-environment": "@dev",
|
||||
"automattic/phpunit-select-config": "^1.0.1"
|
||||
"automattic/phpunit-select-config": "^1.0.3"
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
|
||||
@ -328,7 +328,7 @@ class Throw_On_Errors {
|
||||
*
|
||||
* @param string $directory Directory that will be scanned.
|
||||
*
|
||||
* @return string An array of filenames.
|
||||
* @return string[] An array of filenames.
|
||||
* @throws Exception If scandir() has thrown warnings, or has failed.
|
||||
*/
|
||||
public static function t_scandir( $directory ) {
|
||||
|
||||
@ -5,6 +5,42 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.4.3] - 2026-02-23
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [0.4.2] - 2026-02-02
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [0.4.1] - 2025-12-08
|
||||
### Fixed
|
||||
- Ensure proper flags are used with `json_encode()`. [#46092]
|
||||
|
||||
## [0.4.0] - 2025-11-17
|
||||
### Added
|
||||
- General: Add a daily cleanup of expired transients. [#45920]
|
||||
|
||||
## [0.3.14] - 2025-10-20
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.3.13] - 2025-09-08
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.3.12] - 2025-08-04
|
||||
### Added
|
||||
- Add helper to clear all custom transients at the same time. [#44549]
|
||||
|
||||
## [0.3.11] - 2025-06-23
|
||||
### Fixed
|
||||
- General: Ensure the correct home page is checked when sites are in a subfolder. [#44007]
|
||||
|
||||
## [0.3.10] - 2025-04-28
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.3.9] - 2025-03-21
|
||||
### Changed
|
||||
- Internal updates.
|
||||
@ -125,6 +161,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
- Introduce new package. [#31163]
|
||||
|
||||
[0.4.3]: https://github.com/Automattic/jetpack-boost-core/compare/v0.4.2...v0.4.3
|
||||
[0.4.2]: https://github.com/Automattic/jetpack-boost-core/compare/v0.4.1...v0.4.2
|
||||
[0.4.1]: https://github.com/Automattic/jetpack-boost-core/compare/v0.4.0...v0.4.1
|
||||
[0.4.0]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.14...v0.4.0
|
||||
[0.3.14]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.13...v0.3.14
|
||||
[0.3.13]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.12...v0.3.13
|
||||
[0.3.12]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.11...v0.3.12
|
||||
[0.3.11]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.10...v0.3.11
|
||||
[0.3.10]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.9...v0.3.10
|
||||
[0.3.9]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.8...v0.3.9
|
||||
[0.3.8]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.7...v0.3.8
|
||||
[0.3.7]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.6...v0.3.7
|
||||
|
||||
@ -9,24 +9,23 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
<https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
@ -36,48 +35,48 @@ using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
@ -94,7 +93,7 @@ is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
@ -105,29 +104,29 @@ along with the Program.
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
@ -149,26 +148,26 @@ with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
@ -187,7 +186,7 @@ access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
@ -195,7 +194,7 @@ However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
@ -204,7 +203,7 @@ Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
@ -212,7 +211,7 @@ restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
@ -244,7 +243,7 @@ impose that choice.
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
@ -252,7 +251,7 @@ those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
@ -265,7 +264,7 @@ Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
@ -273,9 +272,9 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
@ -285,7 +284,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
@ -295,45 +294,44 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
@ -344,11 +342,11 @@ You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
|
||||
@ -5,12 +5,12 @@
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"automattic/jetpack-connection": "^6.7.7"
|
||||
"automattic/jetpack-connection": "^8.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "^3.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.2",
|
||||
"automattic/phpunit-select-config": "^1.0.1"
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.14",
|
||||
"automattic/phpunit-select-config": "^1.0.3"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
@ -37,7 +37,7 @@
|
||||
},
|
||||
"autotagger": true,
|
||||
"branch-alias": {
|
||||
"dev-trunk": "0.3.x-dev"
|
||||
"dev-trunk": "0.4.x-dev"
|
||||
},
|
||||
"textdomain": "jetpack-boost-core"
|
||||
},
|
||||
|
||||
@ -72,6 +72,34 @@ class Transient {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all expired transients.
|
||||
*
|
||||
* @return int The number of deleted transients.
|
||||
*/
|
||||
public static function delete_expired() {
|
||||
global $wpdb;
|
||||
|
||||
//phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$option_names = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s",
|
||||
self::OPTION_PREFIX . '%'
|
||||
)
|
||||
);
|
||||
|
||||
$count = 0;
|
||||
foreach ( $option_names as $option_name ) {
|
||||
$value = get_option( $option_name );
|
||||
if ( isset( $value['expire'] ) && $value['expire'] < time() ) {
|
||||
delete_option( $option_name );
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all `Transient` values with certain prefix from database.
|
||||
*
|
||||
@ -109,6 +137,33 @@ class Transient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all `Transient` values from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function delete_bulk() {
|
||||
global $wpdb;
|
||||
|
||||
$prefix_search_pattern = $wpdb->esc_like( self::OPTION_PREFIX ) . '%';
|
||||
|
||||
//phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"DELETE FROM $wpdb->options WHERE option_name LIKE %s",
|
||||
$prefix_search_pattern
|
||||
)
|
||||
);
|
||||
|
||||
if (
|
||||
function_exists( 'wp_cache_flush_group' ) &&
|
||||
function_exists( 'wp_cache_supports' ) &&
|
||||
wp_cache_supports( 'flush_group' )
|
||||
) {
|
||||
wp_cache_flush_group( 'options' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache entry.
|
||||
*
|
||||
|
||||
@ -38,7 +38,7 @@ class Utils {
|
||||
if ( is_object( $error ) ) {
|
||||
return array(
|
||||
'name' => 'Error',
|
||||
'message' => json_decode( wp_json_encode( $error ), ARRAY_A ),
|
||||
'message' => json_decode( wp_json_encode( $error, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ), true ),
|
||||
);
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ class Utils {
|
||||
*/
|
||||
public static function force_url_to_absolute( $url ) {
|
||||
if ( str_starts_with( $url, '/' ) ) {
|
||||
return get_site_url( null, $url );
|
||||
return home_url( $url );
|
||||
}
|
||||
|
||||
return $url;
|
||||
@ -114,7 +114,7 @@ class Utils {
|
||||
$endpoint,
|
||||
'2',
|
||||
array_merge( $default_args, empty( $args ) ? array() : $args ),
|
||||
empty( $body ) ? null : wp_json_encode( $body ),
|
||||
empty( $body ) ? null : wp_json_encode( $body, JSON_UNESCAPED_SLASHES ),
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
@ -124,7 +124,7 @@ class Utils {
|
||||
|
||||
// Check for HTTP errors.
|
||||
$code = wp_remote_retrieve_response_code( $response );
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ), ARRAY_A );
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
if ( 200 !== $code ) {
|
||||
$default_message = sprintf(
|
||||
|
||||
@ -9,6 +9,10 @@ namespace Automattic\Jetpack\Boost_Core\Lib;
|
||||
|
||||
use Automattic\Jetpack\Boost_Core\Contracts\Boost_API_Client;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that handles the Boost API client.
|
||||
*
|
||||
|
||||
@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.4.13] - 2026-04-10
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.4.12] - 2025-11-17
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.4.11] - 2025-10-20
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.4.10] - 2025-07-21
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.4.9] - 2025-05-15
|
||||
### Changed
|
||||
- Switch from deprecated `jetpack_boost_critical_css_environment_changed` action to `jetpack_boost_environment_changed`. [#43446]
|
||||
|
||||
## [0.4.8] - 2025-04-28
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.4.7] - 2025-03-26
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [0.4.6] - 2025-03-21
|
||||
### Changed
|
||||
- Internal updates.
|
||||
@ -124,6 +152,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Add a new package for Boost Speed Score [#30914]
|
||||
- Add a new argument to `Speed_Score` to identify where the request was made from (e.g. 'boost-plugin', 'jetpack-dashboard', etc). [#31012]
|
||||
|
||||
[0.4.13]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.12...v0.4.13
|
||||
[0.4.12]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.11...v0.4.12
|
||||
[0.4.11]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.10...v0.4.11
|
||||
[0.4.10]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.9...v0.4.10
|
||||
[0.4.9]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.8...v0.4.9
|
||||
[0.4.8]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.7...v0.4.8
|
||||
[0.4.7]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.6...v0.4.7
|
||||
[0.4.6]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.5...v0.4.6
|
||||
[0.4.5]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.4...v0.4.5
|
||||
[0.4.4]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.3...v0.4.4
|
||||
|
||||
@ -9,24 +9,23 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
<https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
@ -36,48 +35,48 @@ using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
@ -94,7 +93,7 @@ is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
@ -105,29 +104,29 @@ along with the Program.
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
@ -149,26 +148,26 @@ with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
@ -187,7 +186,7 @@ access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
@ -195,7 +194,7 @@ However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
@ -204,7 +203,7 @@ Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
@ -212,7 +211,7 @@ restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
@ -244,7 +243,7 @@ impose that choice.
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
@ -252,7 +251,7 @@ those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
@ -265,7 +264,7 @@ Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
@ -273,9 +272,9 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
@ -285,7 +284,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
@ -295,45 +294,44 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
@ -344,11 +342,11 @@ You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "^3.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.2",
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.14",
|
||||
"brain/monkey": "^2.6",
|
||||
"automattic/phpunit-select-config": "^1.0.1"
|
||||
"automattic/phpunit-select-config": "^1.0.4"
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
@ -16,7 +16,7 @@
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"automattic/jetpack-boost-core": "^0.3.9"
|
||||
"automattic/jetpack-boost-core": "^0.4.3"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
|
||||
@ -11,6 +11,10 @@ use Automattic\Jetpack\Boost_Core\Lib\Boost_API;
|
||||
use Automattic\Jetpack\Boost_Core\Lib\Cacheable;
|
||||
use Automattic\Jetpack\Boost_Core\Lib\Url;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Speed_Score_Request
|
||||
*/
|
||||
|
||||
@ -20,10 +20,12 @@ if ( ! defined( 'JETPACK_BOOST_REST_PREFIX' ) ) {
|
||||
|
||||
/**
|
||||
* Class Speed_Score
|
||||
*
|
||||
* @phan-constructor-used-for-side-effects
|
||||
*/
|
||||
class Speed_Score {
|
||||
|
||||
const PACKAGE_VERSION = '0.4.6';
|
||||
const PACKAGE_VERSION = '0.4.13';
|
||||
|
||||
/**
|
||||
* Array of module slugs that are currently active and can impact speed score.
|
||||
@ -65,10 +67,11 @@ class Speed_Score {
|
||||
* Mark the speed score history as stale when the environment changes.
|
||||
*
|
||||
* @since 0.3.9 - This hook replaced `handle_environment_change` action.
|
||||
* @since $$next-version - jetpack_boost_critical_css_environment_changed has been replaced by jetpack_boost_environment_changed.
|
||||
*/
|
||||
add_action( 'jetpack_boost_critical_css_environment_changed', array( Speed_Score_History::class, 'mark_stale' ) );
|
||||
add_action( 'jetpack_boost_environment_changed', array( Speed_Score_History::class, 'mark_stale' ) );
|
||||
/**
|
||||
* The `handle_environment_change` action is replaced by `jetpack_boost_critical_css_environment_changed` in Jetpack Boost.
|
||||
* The `handle_environment_change` action is replaced by `jetpack_boost_environment_changed` in Jetpack Boost.
|
||||
* Keeping the `handle_environment_change` action for backward compatibility.
|
||||
*/
|
||||
add_action( 'handle_environment_change', array( Speed_Score_History::class, 'mark_stale' ) );
|
||||
|
||||
@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [3.1.1] - 2025-06-19
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [3.1.0] - 2025-03-26
|
||||
### Added
|
||||
- Adds Account Protection initialization [#40925]
|
||||
|
||||
## [3.0.1] - 2025-02-24
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
@ -216,6 +224,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Trying to add deterministic initialization.
|
||||
|
||||
[3.1.1]: https://github.com/Automattic/jetpack-config/compare/v3.1.0...v3.1.1
|
||||
[3.1.0]: https://github.com/Automattic/jetpack-config/compare/v3.0.1...v3.1.0
|
||||
[3.0.1]: https://github.com/Automattic/jetpack-config/compare/v3.0.0...v3.0.1
|
||||
[3.0.0]: https://github.com/Automattic/jetpack-config/compare/v2.0.4...v3.0.0
|
||||
[2.0.4]: https://github.com/Automattic/jetpack-config/compare/v2.0.3...v2.0.4
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"automattic/jetpack-changelogger": "^6.0.0",
|
||||
"automattic/jetpack-changelogger": "^6.0.5",
|
||||
"automattic/jetpack-connection": "@dev",
|
||||
"automattic/jetpack-import": "@dev",
|
||||
"automattic/jetpack-jitm": "@dev",
|
||||
@ -18,8 +18,8 @@
|
||||
"automattic/jetpack-stats-admin": "@dev",
|
||||
"automattic/jetpack-sync": "@dev",
|
||||
"automattic/jetpack-videopress": "@dev",
|
||||
"automattic/jetpack-account-protection": "@dev",
|
||||
"automattic/jetpack-waf": "@dev",
|
||||
"automattic/jetpack-wordads": "@dev",
|
||||
"automattic/jetpack-yoast-promo": "@dev"
|
||||
},
|
||||
"suggest": {
|
||||
@ -40,22 +40,22 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-config/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "3.0.x-dev"
|
||||
"dev-trunk": "3.1.x-dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"test-only": [
|
||||
"packages/account-protection",
|
||||
"packages/connection",
|
||||
"packages/import",
|
||||
"packages/jitm",
|
||||
"packages/post-list",
|
||||
"packages/publicize",
|
||||
"packages/search",
|
||||
"packages/stats",
|
||||
"packages/stats-admin",
|
||||
"packages/stats",
|
||||
"packages/sync",
|
||||
"packages/videopress",
|
||||
"packages/waf",
|
||||
"packages/wordads",
|
||||
"packages/yoast-promo"
|
||||
]
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ namespace Automattic\Jetpack;
|
||||
* contain the package classes shown below. The consumer plugin
|
||||
* must require the corresponding packages to use these features.
|
||||
*/
|
||||
use Automattic\Jetpack\Account_Protection\Account_Protection as Jetpack_Account_Protection_Main;
|
||||
use Automattic\Jetpack\Connection\Manager;
|
||||
use Automattic\Jetpack\Connection\Plugin;
|
||||
use Automattic\Jetpack\Import\Main as Import_Main;
|
||||
@ -24,7 +25,6 @@ use Automattic\Jetpack\Stats_Admin\Main as Stats_Admin_Main;
|
||||
use Automattic\Jetpack\Sync\Main as Sync_Main;
|
||||
use Automattic\Jetpack\VideoPress\Initializer as VideoPress_Pkg_Initializer;
|
||||
use Automattic\Jetpack\Waf\Waf_Initializer as Jetpack_Waf_Main;
|
||||
use Automattic\Jetpack\WordAds\Initializer as Jetpack_WordAds_Main;
|
||||
|
||||
/**
|
||||
* The configuration class.
|
||||
@ -41,20 +41,20 @@ class Config {
|
||||
* @var Array
|
||||
*/
|
||||
protected $config = array(
|
||||
'jitm' => false,
|
||||
'connection' => false,
|
||||
'sync' => false,
|
||||
'post_list' => false,
|
||||
'identity_crisis' => false,
|
||||
'search' => false,
|
||||
'publicize' => false,
|
||||
'wordads' => false,
|
||||
'waf' => false,
|
||||
'videopress' => false,
|
||||
'stats' => false,
|
||||
'stats_admin' => false,
|
||||
'yoast_promo' => false,
|
||||
'import' => false,
|
||||
'jitm' => false,
|
||||
'connection' => false,
|
||||
'sync' => false,
|
||||
'post_list' => false,
|
||||
'identity_crisis' => false,
|
||||
'search' => false,
|
||||
'publicize' => false,
|
||||
'account_protection' => false,
|
||||
'waf' => false,
|
||||
'videopress' => false,
|
||||
'stats' => false,
|
||||
'stats_admin' => false,
|
||||
'yoast_promo' => false,
|
||||
'import' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
@ -139,9 +139,9 @@ class Config {
|
||||
&& $this->ensure_feature( 'publicize' );
|
||||
}
|
||||
|
||||
if ( $this->config['wordads'] ) {
|
||||
$this->ensure_class( 'Automattic\Jetpack\WordAds\Initializer' )
|
||||
&& $this->ensure_feature( 'wordads' );
|
||||
if ( $this->config['account_protection'] ) {
|
||||
$this->ensure_class( 'Automattic\Jetpack\Account_Protection\Account_Protection' )
|
||||
&& $this->ensure_feature( 'account_protection' );
|
||||
}
|
||||
|
||||
if ( $this->config['waf'] ) {
|
||||
@ -303,10 +303,13 @@ class Config {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables WordAds.
|
||||
* Enables Account Protection.
|
||||
*/
|
||||
protected function enable_wordads() {
|
||||
Jetpack_WordAds_Main::init();
|
||||
protected function enable_account_protection() {
|
||||
$account_protection = Jetpack_Account_Protection_Main::instance();
|
||||
$account_protection->initialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,6 +5,418 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [8.2.2] - 2026-04-10
|
||||
### Changed
|
||||
- Update dependencies. [#46383]
|
||||
|
||||
## [8.2.1] - 2026-04-09
|
||||
### Changed
|
||||
- Update package dependencies. [#47890] [#47998]
|
||||
|
||||
## [8.2.0] - 2026-04-06
|
||||
### Added
|
||||
- Add SSO details to the Connection details card. [#47861]
|
||||
- Add WordPress.com connector card for the WP 7.0+ Settings > Connectors screen with connection details and disconnect support. [#47792]
|
||||
- Connection: Display inline error notices for site registration, authorization, and disconnect failures in the WordPress.com Connectors card. [#47865]
|
||||
|
||||
### Changed
|
||||
- Connector card: Prevent site disconnection and owner account unlinking on Wordpress.com and VIP sites. [#47862]
|
||||
|
||||
### Fixed
|
||||
- Connection Details: Fix layout of the connection details modal to properly handle varying URL lengths and screen sizes. [#47879]
|
||||
- Fix connection flow in connector card when using Gutenberg and ensure modals always show on disconnection. [#47902]
|
||||
- Update Woo logo on connector card. [#47884]
|
||||
|
||||
## [8.1.0] - 2026-03-30
|
||||
### Changed
|
||||
- Replace transient-based SSO broker URL storage with a constant-based approach gated by a WordPress.com authorization signal, and fall back to WordPress.com SSO when the referrer is a WordPress.com domain. [#47630]
|
||||
- Update package dependencies. [#47818]
|
||||
|
||||
### Fixed
|
||||
- Fixed SSO login conflict with Two-Factor plugin 0.15.0+ that caused a redundant local 2FA prompt after completing WordPress.com 2FA. [#47306]
|
||||
|
||||
## [8.0.5] - 2026-03-23
|
||||
### Changed
|
||||
- Update package dependencies. [#47684]
|
||||
|
||||
## [8.0.4] - 2026-03-16
|
||||
### Changed
|
||||
- Update dependencies. [#47472]
|
||||
|
||||
## [8.0.3] - 2026-03-09
|
||||
### Changed
|
||||
- Update package dependencies. [#47496]
|
||||
|
||||
## [8.0.2] - 2026-03-02
|
||||
### Changed
|
||||
- Update dependencies. [#46383]
|
||||
|
||||
## [8.0.1] - 2026-02-26
|
||||
### Changed
|
||||
- Update package dependencies. [#47300]
|
||||
|
||||
## [8.0.0] - 2026-02-23
|
||||
### Removed
|
||||
- Remove deprecated methods and attributes. [#47251]
|
||||
|
||||
## [7.1.1] - 2026-02-18
|
||||
### Changed
|
||||
- Update package dependencies. [#47173]
|
||||
|
||||
## [7.1.0] - 2026-02-16
|
||||
### Added
|
||||
- Add `maybe_add_origin_site_id` method to the `Urls` class. [#46783]
|
||||
|
||||
### Changed
|
||||
- Update package dependencies. [#47099]
|
||||
|
||||
## [7.0.3] - 2026-02-10
|
||||
### Changed
|
||||
- Move IDC stats from Jetpack plugin to connection package. [#46967]
|
||||
- Update package dependencies. [#47002]
|
||||
|
||||
## [7.0.2] - 2026-02-04
|
||||
### Changed
|
||||
- Update package dependencies. [#46936]
|
||||
|
||||
## [7.0.1] - 2026-02-03
|
||||
### Changed
|
||||
- Update dependencies. [#46383]
|
||||
|
||||
## [7.0.0] - 2026-02-02
|
||||
### Changed
|
||||
- Remove error handling methods for external storage and add host agnostic error reporting. [#46646]
|
||||
- Update package dependencies. [#46854]
|
||||
|
||||
## [6.20.5] - 2026-01-26
|
||||
### Changed
|
||||
- Update dependencies. [#46383]
|
||||
|
||||
## [6.20.4] - 2026-01-23
|
||||
### Added
|
||||
- IDC: Preserve re-validation parameters when new idc error is created. [#46613]
|
||||
|
||||
## [6.20.3] - 2026-01-19
|
||||
### Changed
|
||||
- Update package dependencies. [#46647]
|
||||
|
||||
## [6.20.2] - 2026-01-14
|
||||
### Changed
|
||||
- Update package dependencies. [#46552]
|
||||
|
||||
## [6.20.1] - 2026-01-12
|
||||
### Changed
|
||||
- Add transients to prevent excessive remote calls. [#46503]
|
||||
|
||||
## [6.20.0] - 2026-01-07
|
||||
### Added
|
||||
- IDC: Add revalidation for IDCs. [#46268]
|
||||
|
||||
### Changed
|
||||
- Update package dependencies. [#46456]
|
||||
|
||||
## [6.19.13] - 2025-12-22
|
||||
### Changed
|
||||
- Update dependencies. [#46381]
|
||||
|
||||
## [6.19.12] - 2025-12-15
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.19.11] - 2025-12-11
|
||||
### Removed
|
||||
- Development Mode: removed references to previously removed code [#46231]
|
||||
|
||||
## [6.19.10] - 2025-12-08
|
||||
### Fixed
|
||||
- Ensure proper flags are used with `json_encode()`. [#46092]
|
||||
|
||||
## [6.19.9] - 2025-12-01
|
||||
### Changed
|
||||
- SSO: Revised copy for flagging external collaborators. [#46108]
|
||||
- Update package dependencies. [#46143]
|
||||
|
||||
## [6.19.8] - 2025-11-20
|
||||
### Fixed
|
||||
- Phan: Address PhanPossiblyUndeclaredVariable violations. [#45911]
|
||||
|
||||
## [6.19.7] - 2025-11-18
|
||||
### Changed
|
||||
- Update package dependencies. [#45961]
|
||||
|
||||
## [6.19.6] - 2025-11-17
|
||||
### Changed
|
||||
- Update package dependencies. [#45915]
|
||||
|
||||
## [6.19.5] - 2025-11-12
|
||||
### Fixed
|
||||
- OAuth: fix the 'body-hash' error triggered during app authorization. [#45820]
|
||||
|
||||
## [6.19.4] - 2025-11-10
|
||||
### Changed
|
||||
- Tests: Improve compatibility with PHP 8.5. [#45769] [#45771]
|
||||
|
||||
## [6.19.3] - 2025-11-03
|
||||
### Changed
|
||||
- Update dependencies. [#45493]
|
||||
|
||||
## [6.19.2] - 2025-10-28
|
||||
### Changed
|
||||
- Update dependencies. [#45493]
|
||||
|
||||
## [6.19.1] - 2025-10-27
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.19.0] - 2025-10-20
|
||||
### Added
|
||||
- Add Newspack and VIP check to `should_allow_error_filtering`. [#45481]
|
||||
|
||||
## [6.18.14] - 2025-10-14
|
||||
### Changed
|
||||
- Update dependencies. [#45488]
|
||||
|
||||
## [6.18.13] - 2025-10-09
|
||||
### Changed
|
||||
- Update error logging for external storage. [#45412]
|
||||
|
||||
## [6.18.12] - 2025-10-02
|
||||
### Changed
|
||||
- Update package dependencies. [#45334]
|
||||
|
||||
## [6.18.11] - 2025-09-29
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.18.10] - 2025-09-22
|
||||
### Changed
|
||||
- Update dependencies. [#44300]
|
||||
|
||||
## [6.18.9] - 2025-09-19
|
||||
### Changed
|
||||
- Update package dependencies. [#45173] [#45229]
|
||||
|
||||
## [6.18.8] - 2025-09-16
|
||||
### Fixed
|
||||
- Prevent PHP warnings when handling invalid user data. [#45198]
|
||||
|
||||
## [6.18.7] - 2025-09-15
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.18.6] - 2025-09-08
|
||||
### Changed
|
||||
- Update package dependencies. [#45027]
|
||||
|
||||
## [6.18.5] - 2025-09-01
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.18.4] - 2025-08-25
|
||||
### Changed
|
||||
- Update dependencies. [#44300]
|
||||
|
||||
## [6.18.3] - 2025-08-25
|
||||
### Fixed
|
||||
- Code: Resolve PhanImpossibleCondition violations. [#44869]
|
||||
- Fix fatal for invalid structure of stored errors. [#44890]
|
||||
|
||||
## [6.18.2] - 2025-08-21
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.18.1] - 2025-08-18
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.18.0] - 2025-08-14
|
||||
### Added
|
||||
- Create External_Storage class. [#44631]
|
||||
|
||||
## [6.17.2] - 2025-08-13
|
||||
### Changed
|
||||
- Update package dependencies. [#44701]
|
||||
|
||||
## [6.17.1] - 2025-08-11
|
||||
### Changed
|
||||
- Update package dependencies. [#44677]
|
||||
|
||||
## [6.17.0] - 2025-08-04
|
||||
### Added
|
||||
- Extend `get_option` so it can work with external storage. [#44554]
|
||||
|
||||
### Changed
|
||||
- Update connection webhooks to pass skip_pricing to authorization URL. [#44603]
|
||||
|
||||
## [6.16.2] - 2025-07-30
|
||||
### Fixed
|
||||
- Fix doc types for methods in the connection Manager class. [#44493]
|
||||
|
||||
## [6.16.1] - 2025-07-28
|
||||
### Fixed
|
||||
- Fix a fatal triggered by trying to disconnect Jetpack too early. [#44435]
|
||||
|
||||
## [6.16.0] - 2025-07-23
|
||||
### Changed
|
||||
- Connection: Remove hard-coded custom errors and added support for dynamic errors. [#44281]
|
||||
|
||||
## [6.15.0] - 2025-07-21
|
||||
### Added
|
||||
- Add memoization for connection owner ID to prevent excessive database calls. [#44282]
|
||||
|
||||
### Changed
|
||||
- Update package dependencies. [#44356]
|
||||
|
||||
## [6.14.2] - 2025-07-14
|
||||
### Changed
|
||||
- Update dependencies. [#44271]
|
||||
|
||||
## [6.14.1] - 2025-07-08
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.14.0] - 2025-07-07
|
||||
### Changed
|
||||
- Scripts: Ensure host-related checks and functionality are only added via Assets. [#44133]
|
||||
|
||||
## [6.13.13] - 2025-07-03
|
||||
### Changed
|
||||
- Update package dependencies. [#44151]
|
||||
|
||||
## [6.13.12] - 2025-07-01
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [6.13.11] - 2025-06-30
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.13.10] - 2025-06-27
|
||||
### Changed
|
||||
- Refactor connection error handling so all prompts have the same messages. [#44042]
|
||||
|
||||
## [6.13.9] - 2025-06-24
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.13.8] - 2025-06-23
|
||||
### Fixed
|
||||
- Autoloader: Prevent double slash in autoloader path. [#44030]
|
||||
|
||||
## [6.13.7] - 2025-06-23
|
||||
### Changed
|
||||
- Update package dependencies. [#44020]
|
||||
|
||||
## [6.13.6] - 2025-06-19
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.13.5] - 2025-06-18
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.13.4] - 2025-06-16
|
||||
### Changed
|
||||
- Update package dependencies. [#43914]
|
||||
|
||||
## [6.13.3] - 2025-06-10
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.13.2] - 2025-06-09
|
||||
### Fixed
|
||||
- Tests: Ensure method param count matches PHPUnit data providers. [#43828]
|
||||
|
||||
## [6.13.1] - 2025-06-06
|
||||
### Fixed
|
||||
- Tests: Resolve warnings in PHPUnit 12.2. [#43815]
|
||||
|
||||
## [6.13.0] - 2025-06-05
|
||||
### Changed
|
||||
- Limit access to manage connection dialog on WoA sites. [#43777]
|
||||
|
||||
## [6.12.0] - 2025-06-04
|
||||
### Added
|
||||
- Improve error handling for protected owner on WordPress.com. [#43593]
|
||||
|
||||
## [6.11.9] - 2025-06-03
|
||||
### Changed
|
||||
- Update package dependencies. [#43734]
|
||||
|
||||
## [6.11.8] - 2025-06-02
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.11.7] - 2025-05-26
|
||||
### Changed
|
||||
- Update package dependencies. [#43578]
|
||||
|
||||
## [6.11.6] - 2025-05-22
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.11.5] - 2025-05-19
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.11.4] - 2025-05-15
|
||||
### Changed
|
||||
- Update package dependencies. [#43398]
|
||||
|
||||
## [6.11.3] - 2025-05-12
|
||||
### Changed
|
||||
- Stable release management: Do not ship source files. [#43310]
|
||||
- Update package dependencies. [#43400]
|
||||
|
||||
## [6.11.2] - 2025-05-05
|
||||
### Changed
|
||||
- Update package dependencies. [#43326] [#43353]
|
||||
|
||||
### Removed
|
||||
- Remove auth providers support. [#43241]
|
||||
|
||||
## [6.11.1] - 2025-04-28
|
||||
### Changed
|
||||
- Jetpack Sync: Switch `jetpack_package_version` to a callable. [#43188]
|
||||
|
||||
### Fixed
|
||||
- Linting: Fix more Stylelint violations. [#43213]
|
||||
|
||||
## [6.11.0] - 2025-04-14
|
||||
### Added
|
||||
- Add check for mismatched WordPress/WordPress.com user email. [#42674]
|
||||
|
||||
### Changed
|
||||
- Add Jetpack package version info to Heartbeat. [#43060]
|
||||
|
||||
### Fixed
|
||||
- Linting: Update stylesheets to use WordPress rules for fonts and colors. [#42920] [#42928]
|
||||
- Linting: Use double colon notation for pseudo-element selectors. [#43019]
|
||||
|
||||
## [6.10.3] - 2025-04-07
|
||||
### Changed
|
||||
- Linting: First pass of style coding standards. [#42734]
|
||||
|
||||
## [6.10.2] - 2025-04-01
|
||||
### Changed
|
||||
- Update package dependencies. [#42809]
|
||||
|
||||
## [6.10.1] - 2025-04-01
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
|
||||
## [6.10.0] - 2025-03-31
|
||||
### Added
|
||||
- IDC: Add "Offline Mode" flag to secret check endpoint. [#42779]
|
||||
|
||||
## [6.9.0] - 2025-03-26
|
||||
### Added
|
||||
- Connection: Allow pre-selected login providers. [#42662]
|
||||
- Indicate when Offline Mode is enabled via DB option. [#42630]
|
||||
|
||||
### Changed
|
||||
- Connection: Register assets absolutely. [#42468]
|
||||
|
||||
## [6.8.1] - 2025-03-24
|
||||
### Changed
|
||||
- Update dependencies.
|
||||
@ -1370,6 +1782,97 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Separate the connection library into its own package.
|
||||
|
||||
[8.2.2]: https://github.com/Automattic/jetpack-connection/compare/v8.2.1...v8.2.2
|
||||
[8.2.1]: https://github.com/Automattic/jetpack-connection/compare/v8.2.0...v8.2.1
|
||||
[8.2.0]: https://github.com/Automattic/jetpack-connection/compare/v8.1.0...v8.2.0
|
||||
[8.1.0]: https://github.com/Automattic/jetpack-connection/compare/v8.0.5...v8.1.0
|
||||
[8.0.5]: https://github.com/Automattic/jetpack-connection/compare/v8.0.4...v8.0.5
|
||||
[8.0.4]: https://github.com/Automattic/jetpack-connection/compare/v8.0.3...v8.0.4
|
||||
[8.0.3]: https://github.com/Automattic/jetpack-connection/compare/v8.0.2...v8.0.3
|
||||
[8.0.2]: https://github.com/Automattic/jetpack-connection/compare/v8.0.1...v8.0.2
|
||||
[8.0.1]: https://github.com/Automattic/jetpack-connection/compare/v8.0.0...v8.0.1
|
||||
[8.0.0]: https://github.com/Automattic/jetpack-connection/compare/v7.1.1...v8.0.0
|
||||
[7.1.1]: https://github.com/Automattic/jetpack-connection/compare/v7.1.0...v7.1.1
|
||||
[7.1.0]: https://github.com/Automattic/jetpack-connection/compare/v7.0.3...v7.1.0
|
||||
[7.0.3]: https://github.com/Automattic/jetpack-connection/compare/v7.0.2...v7.0.3
|
||||
[7.0.2]: https://github.com/Automattic/jetpack-connection/compare/v7.0.1...v7.0.2
|
||||
[7.0.1]: https://github.com/Automattic/jetpack-connection/compare/v7.0.0...v7.0.1
|
||||
[7.0.0]: https://github.com/Automattic/jetpack-connection/compare/v6.20.5...v7.0.0
|
||||
[6.20.5]: https://github.com/Automattic/jetpack-connection/compare/v6.20.4...v6.20.5
|
||||
[6.20.4]: https://github.com/Automattic/jetpack-connection/compare/v6.20.3...v6.20.4
|
||||
[6.20.3]: https://github.com/Automattic/jetpack-connection/compare/v6.20.2...v6.20.3
|
||||
[6.20.2]: https://github.com/Automattic/jetpack-connection/compare/v6.20.1...v6.20.2
|
||||
[6.20.1]: https://github.com/Automattic/jetpack-connection/compare/v6.20.0...v6.20.1
|
||||
[6.20.0]: https://github.com/Automattic/jetpack-connection/compare/v6.19.13...v6.20.0
|
||||
[6.19.13]: https://github.com/Automattic/jetpack-connection/compare/v6.19.12...v6.19.13
|
||||
[6.19.12]: https://github.com/Automattic/jetpack-connection/compare/v6.19.11...v6.19.12
|
||||
[6.19.11]: https://github.com/Automattic/jetpack-connection/compare/v6.19.10...v6.19.11
|
||||
[6.19.10]: https://github.com/Automattic/jetpack-connection/compare/v6.19.9...v6.19.10
|
||||
[6.19.9]: https://github.com/Automattic/jetpack-connection/compare/v6.19.8...v6.19.9
|
||||
[6.19.8]: https://github.com/Automattic/jetpack-connection/compare/v6.19.7...v6.19.8
|
||||
[6.19.7]: https://github.com/Automattic/jetpack-connection/compare/v6.19.6...v6.19.7
|
||||
[6.19.6]: https://github.com/Automattic/jetpack-connection/compare/v6.19.5...v6.19.6
|
||||
[6.19.5]: https://github.com/Automattic/jetpack-connection/compare/v6.19.4...v6.19.5
|
||||
[6.19.4]: https://github.com/Automattic/jetpack-connection/compare/v6.19.3...v6.19.4
|
||||
[6.19.3]: https://github.com/Automattic/jetpack-connection/compare/v6.19.2...v6.19.3
|
||||
[6.19.2]: https://github.com/Automattic/jetpack-connection/compare/v6.19.1...v6.19.2
|
||||
[6.19.1]: https://github.com/Automattic/jetpack-connection/compare/v6.19.0...v6.19.1
|
||||
[6.19.0]: https://github.com/Automattic/jetpack-connection/compare/v6.18.14...v6.19.0
|
||||
[6.18.14]: https://github.com/Automattic/jetpack-connection/compare/v6.18.13...v6.18.14
|
||||
[6.18.13]: https://github.com/Automattic/jetpack-connection/compare/v6.18.12...v6.18.13
|
||||
[6.18.12]: https://github.com/Automattic/jetpack-connection/compare/v6.18.11...v6.18.12
|
||||
[6.18.11]: https://github.com/Automattic/jetpack-connection/compare/v6.18.10...v6.18.11
|
||||
[6.18.10]: https://github.com/Automattic/jetpack-connection/compare/v6.18.9...v6.18.10
|
||||
[6.18.9]: https://github.com/Automattic/jetpack-connection/compare/v6.18.8...v6.18.9
|
||||
[6.18.8]: https://github.com/Automattic/jetpack-connection/compare/v6.18.7...v6.18.8
|
||||
[6.18.7]: https://github.com/Automattic/jetpack-connection/compare/v6.18.6...v6.18.7
|
||||
[6.18.6]: https://github.com/Automattic/jetpack-connection/compare/v6.18.5...v6.18.6
|
||||
[6.18.5]: https://github.com/Automattic/jetpack-connection/compare/v6.18.4...v6.18.5
|
||||
[6.18.4]: https://github.com/Automattic/jetpack-connection/compare/v6.18.3...v6.18.4
|
||||
[6.18.3]: https://github.com/Automattic/jetpack-connection/compare/v6.18.2...v6.18.3
|
||||
[6.18.2]: https://github.com/Automattic/jetpack-connection/compare/v6.18.1...v6.18.2
|
||||
[6.18.1]: https://github.com/Automattic/jetpack-connection/compare/v6.18.0...v6.18.1
|
||||
[6.18.0]: https://github.com/Automattic/jetpack-connection/compare/v6.17.2...v6.18.0
|
||||
[6.17.2]: https://github.com/Automattic/jetpack-connection/compare/v6.17.1...v6.17.2
|
||||
[6.17.1]: https://github.com/Automattic/jetpack-connection/compare/v6.17.0...v6.17.1
|
||||
[6.17.0]: https://github.com/Automattic/jetpack-connection/compare/v6.16.2...v6.17.0
|
||||
[6.16.2]: https://github.com/Automattic/jetpack-connection/compare/v6.16.1...v6.16.2
|
||||
[6.16.1]: https://github.com/Automattic/jetpack-connection/compare/v6.16.0...v6.16.1
|
||||
[6.16.0]: https://github.com/Automattic/jetpack-connection/compare/v6.15.0...v6.16.0
|
||||
[6.15.0]: https://github.com/Automattic/jetpack-connection/compare/v6.14.2...v6.15.0
|
||||
[6.14.2]: https://github.com/Automattic/jetpack-connection/compare/v6.14.1...v6.14.2
|
||||
[6.14.1]: https://github.com/Automattic/jetpack-connection/compare/v6.14.0...v6.14.1
|
||||
[6.14.0]: https://github.com/Automattic/jetpack-connection/compare/v6.13.13...v6.14.0
|
||||
[6.13.13]: https://github.com/Automattic/jetpack-connection/compare/v6.13.12...v6.13.13
|
||||
[6.13.12]: https://github.com/Automattic/jetpack-connection/compare/v6.13.11...v6.13.12
|
||||
[6.13.11]: https://github.com/Automattic/jetpack-connection/compare/v6.13.10...v6.13.11
|
||||
[6.13.10]: https://github.com/Automattic/jetpack-connection/compare/v6.13.9...v6.13.10
|
||||
[6.13.9]: https://github.com/Automattic/jetpack-connection/compare/v6.13.8...v6.13.9
|
||||
[6.13.8]: https://github.com/Automattic/jetpack-connection/compare/v6.13.7...v6.13.8
|
||||
[6.13.7]: https://github.com/Automattic/jetpack-connection/compare/v6.13.6...v6.13.7
|
||||
[6.13.6]: https://github.com/Automattic/jetpack-connection/compare/v6.13.5...v6.13.6
|
||||
[6.13.5]: https://github.com/Automattic/jetpack-connection/compare/v6.13.4...v6.13.5
|
||||
[6.13.4]: https://github.com/Automattic/jetpack-connection/compare/v6.13.3...v6.13.4
|
||||
[6.13.3]: https://github.com/Automattic/jetpack-connection/compare/v6.13.2...v6.13.3
|
||||
[6.13.2]: https://github.com/Automattic/jetpack-connection/compare/v6.13.1...v6.13.2
|
||||
[6.13.1]: https://github.com/Automattic/jetpack-connection/compare/v6.13.0...v6.13.1
|
||||
[6.13.0]: https://github.com/Automattic/jetpack-connection/compare/v6.12.0...v6.13.0
|
||||
[6.12.0]: https://github.com/Automattic/jetpack-connection/compare/v6.11.9...v6.12.0
|
||||
[6.11.9]: https://github.com/Automattic/jetpack-connection/compare/v6.11.8...v6.11.9
|
||||
[6.11.8]: https://github.com/Automattic/jetpack-connection/compare/v6.11.7...v6.11.8
|
||||
[6.11.7]: https://github.com/Automattic/jetpack-connection/compare/v6.11.6...v6.11.7
|
||||
[6.11.6]: https://github.com/Automattic/jetpack-connection/compare/v6.11.5...v6.11.6
|
||||
[6.11.5]: https://github.com/Automattic/jetpack-connection/compare/v6.11.4...v6.11.5
|
||||
[6.11.4]: https://github.com/Automattic/jetpack-connection/compare/v6.11.3...v6.11.4
|
||||
[6.11.3]: https://github.com/Automattic/jetpack-connection/compare/v6.11.2...v6.11.3
|
||||
[6.11.2]: https://github.com/Automattic/jetpack-connection/compare/v6.11.1...v6.11.2
|
||||
[6.11.1]: https://github.com/Automattic/jetpack-connection/compare/v6.11.0...v6.11.1
|
||||
[6.11.0]: https://github.com/Automattic/jetpack-connection/compare/v6.10.3...v6.11.0
|
||||
[6.10.3]: https://github.com/Automattic/jetpack-connection/compare/v6.10.2...v6.10.3
|
||||
[6.10.2]: https://github.com/Automattic/jetpack-connection/compare/v6.10.1...v6.10.2
|
||||
[6.10.1]: https://github.com/Automattic/jetpack-connection/compare/v6.10.0...v6.10.1
|
||||
[6.10.0]: https://github.com/Automattic/jetpack-connection/compare/v6.9.0...v6.10.0
|
||||
[6.9.0]: https://github.com/Automattic/jetpack-connection/compare/v6.8.1...v6.9.0
|
||||
[6.8.1]: https://github.com/Automattic/jetpack-connection/compare/v6.8.0...v6.8.1
|
||||
[6.8.0]: https://github.com/Automattic/jetpack-connection/compare/v6.7.7...v6.8.0
|
||||
[6.7.7]: https://github.com/Automattic/jetpack-connection/compare/v6.7.6...v6.7.7
|
||||
|
||||
@ -9,24 +9,23 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
<https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
@ -36,48 +35,48 @@ using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
@ -94,7 +93,7 @@ is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
@ -105,29 +104,29 @@ along with the Program.
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
@ -149,26 +148,26 @@ with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
@ -187,7 +186,7 @@ access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
@ -195,7 +194,7 @@ However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
@ -204,7 +203,7 @@ Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
@ -212,7 +211,7 @@ restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
@ -244,7 +243,7 @@ impose that choice.
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
@ -252,7 +251,7 @@ those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
@ -265,7 +264,7 @@ Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
@ -273,9 +272,9 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
@ -285,7 +284,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
@ -295,45 +294,44 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
@ -344,11 +342,11 @@ You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
|
||||
@ -5,11 +5,6 @@
|
||||
* @package automattic/jetpack-connection
|
||||
*/
|
||||
|
||||
if ( function_exists( 'is_admin' ) && ! is_admin() && ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) ) {
|
||||
// Don't initialize the assets in the frontend on self-hosted and WoA.
|
||||
return;
|
||||
}
|
||||
|
||||
// If WordPress's plugin API is available already, use it. If not,
|
||||
// drop data into `$wp_filter` for `WP_Hook::build_preinitialized_hooks()`.
|
||||
if ( function_exists( 'add_action' ) ) {
|
||||
|
||||
@ -5,20 +5,20 @@
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"automattic/jetpack-a8c-mc-stats": "^3.0.4",
|
||||
"automattic/jetpack-admin-ui": "^0.5.7",
|
||||
"automattic/jetpack-assets": "^4.0.14",
|
||||
"automattic/jetpack-constants": "^3.0.5",
|
||||
"automattic/jetpack-roles": "^3.0.5",
|
||||
"automattic/jetpack-status": "^5.0.10",
|
||||
"automattic/jetpack-redirect": "^3.0.5"
|
||||
"automattic/jetpack-a8c-mc-stats": "^3.0.5",
|
||||
"automattic/jetpack-admin-ui": "^0.8.0",
|
||||
"automattic/jetpack-assets": "^4.3.32",
|
||||
"automattic/jetpack-constants": "^3.0.8",
|
||||
"automattic/jetpack-roles": "^3.0.8",
|
||||
"automattic/jetpack-status": "^6.1.2",
|
||||
"automattic/jetpack-redirect": "^3.0.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"automattic/jetpack-test-environment": "@dev",
|
||||
"yoast/phpunit-polyfills": "^3.0.0",
|
||||
"yoast/phpunit-polyfills": "^4.0.0",
|
||||
"brain/monkey": "^2.6.2",
|
||||
"automattic/jetpack-changelogger": "^6.0.2",
|
||||
"automattic/phpunit-select-config": "^1.0.1"
|
||||
"automattic/jetpack-changelogger": "^6.0.14",
|
||||
"automattic/phpunit-select-config": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
@ -64,7 +64,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-connection/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "6.8.x-dev"
|
||||
"dev-trunk": "8.2.x-dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"test-only": [
|
||||
|
||||
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '286b93b23b84729b30b9');
|
||||
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => 'd070b7389357c79ab1f2');
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,17 @@
|
||||
<svg width="380" height="183" viewBox="0 0 380 183" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.75" filter="url(#filter0_f_5953_11924)">
|
||||
<path d="M360 -60C360 7.93102 304.931 63 237 63C169.069 63 114 7.93102 114 -60C114 -127.931 169.069 -183 237 -183C304.931 -183 360 -127.931 360 -60Z" fill="url(#paint0_linear_5953_11924)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_f_5953_11924" x="-6" y="-303" width="486" height="486" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="60" result="effect1_foregroundBlur_5953_11924"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_5953_11924" x1="360" y1="-60" x2="114" y2="-60" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#48FF50"/>
|
||||
<stop offset="0.471846" stop-color="#108642"/>
|
||||
<stop offset="1" stop-color="#2E38FA"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 990 B |
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('jetpack-script-data', 'react', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'c64bcd54b1a8ca23f813');
|
||||
<?php return array('dependencies' => array('jetpack-script-data', 'react', 'react-jsx-runtime', 'wp-components', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '949f850056cf2237951b');
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,7 +0,0 @@
|
||||
/*
|
||||
* Exposes number format capability
|
||||
*
|
||||
* @copyright Copyright (c) 2013 Kevin van Zonneveld (http://kvz.io) and Contributors (http://phpjs.org/authors).
|
||||
* @license See CREDITS.md
|
||||
* @see https://github.com/kvz/phpjs/blob/ffe1356af23a6f2512c84c954dd4e828e92579fa/functions/strings/number_format.js
|
||||
*/
|
||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => 'd0b88193b5b4008c3108');
|
||||
<?php return array('dependencies' => array(), 'version' => 'a3e26c4e5b7f15f38c40');
|
||||
|
||||
@ -1 +1 @@
|
||||
document.addEventListener("DOMContentLoaded",(function(){const e=document.getElementById("send_user_notification"),d=document.getElementById("user_external_contractor"),t=document.getElementById("invite_user_wpcom"),n=document.getElementById("custom_email_message_block");t&&e&&n&&(t.addEventListener("change",(function(){e.disabled=t.checked,t.checked?(e.checked=!1,d&&(d.disabled=!1),n.style.display="table"):(d&&(d.disabled=!0,d.checked=!1),n.style.display="none")})),t.checked&&(e.disabled=!0,e.checked=!1,n.style.display="table"),t.checked||(d&&(d.disabled=!0),n.style.display="none"))}));
|
||||
document.addEventListener("DOMContentLoaded",function(){const e=document.getElementById("send_user_notification"),d=document.getElementById("user_external_contractor"),t=document.getElementById("invite_user_wpcom"),n=document.getElementById("custom_email_message_block");t&&e&&n&&(t.addEventListener("change",function(){e.disabled=t.checked,t.checked?(e.checked=!1,d&&(d.disabled=!1),n.style.display="table"):(d&&(d.disabled=!0,d.checked=!1),n.style.display="none")}),t.checked&&(e.disabled=!0,e.checked=!1,n.style.display="table"),t.checked||(d&&(d.disabled=!0),n.style.display="none"))});
|
||||
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => '049775f3b0a647a127f9');
|
||||
<?php return array('dependencies' => array(), 'version' => 'b2c498fc8d26c8c695b1');
|
||||
|
||||
@ -1 +1 @@
|
||||
document.addEventListener("DOMContentLoaded",(()=>{const e=document.querySelector("body"),t=document.querySelector(".jetpack-sso-toggle"),d=document.getElementById("user_login"),o=document.getElementById("user_pass"),s=document.getElementById("jetpack-sso-wrap"),n=document.getElementById("loginform"),c=document.createElement("div");c.className="jetpack-sso-clear",n.appendChild(c),c.appendChild(document.querySelector("p.forgetmenot")),c.appendChild(document.querySelector("p.submit")),n.appendChild(s),e.classList.add("jetpack-sso-repositioned"),t.addEventListener("click",(t=>{t.preventDefault(),e.classList.toggle("jetpack-sso-form-display"),e.classList.contains("jetpack-sso-form-display")||(d.focus(),o.disabled=!1)}))}));
|
||||
document.addEventListener("DOMContentLoaded",()=>{const e=document.querySelector("body"),t=document.querySelector(".jetpack-sso-toggle"),d=document.getElementById("user_login"),o=document.getElementById("user_pass"),s=document.getElementById("jetpack-sso-wrap"),n=document.getElementById("loginform"),c=document.createElement("div");c.className="jetpack-sso-clear",n.appendChild(c),c.appendChild(document.querySelector("p.forgetmenot")),c.appendChild(document.querySelector("p.submit")),n.appendChild(s),e.classList.add("jetpack-sso-repositioned"),t.addEventListener("click",t=>{t.preventDefault(),e.classList.toggle("jetpack-sso-form-display"),e.classList.contains("jetpack-sso-form-display")||(d.focus(),o.disabled=!1)})});
|
||||
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '15315caa8ea669cf4372');
|
||||
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '9b04da34a7196789f44c');
|
||||
|
||||
@ -1 +1 @@
|
||||
document.addEventListener("DOMContentLoaded",(function(){function t(){this.querySelector(".jetpack-sso-invitation-tooltip").style.display="block"}function e(t){t.target.ownerDocument.activeElement!==t.target&&(this.querySelector(".jetpack-sso-invitation-tooltip").style.display="none")}document.querySelectorAll(".jetpack-sso-invitation-tooltip-icon:not(.sso-disconnected-user)").forEach((function(t){t.innerHTML+=" [?]";const e=document.createElement("span");e.classList.add("jetpack-sso-invitation-tooltip");const n=window.Jetpack_SSOTooltip.tooltipString;function o(){t.appendChild(e),e.style.display="block"}function i(){t.ownerDocument.activeElement!==t&&t.removeChild(e)}e.innerHTML+=n,t.addEventListener("mouseenter",o),t.addEventListener("focus",o),t.addEventListener("mouseleave",i),t.addEventListener("blur",i)})),document.querySelectorAll(".jetpack-sso-invitation-tooltip-icon:not(.jetpack-sso-status-column)").forEach((function(n){n.addEventListener("mouseenter",t),n.addEventListener("focus",t),n.addEventListener("mouseleave",e),n.addEventListener("blur",e)}))}));
|
||||
document.addEventListener("DOMContentLoaded",function(){function t(){this.querySelector(".jetpack-sso-invitation-tooltip").style.display="block"}function e(t){t.target.ownerDocument.activeElement!==t.target&&(this.querySelector(".jetpack-sso-invitation-tooltip").style.display="none")}document.querySelectorAll(".jetpack-sso-invitation-tooltip-icon:not(.sso-disconnected-user)").forEach(function(t){t.innerHTML+=" [?]";const e=document.createElement("span");e.classList.add("jetpack-sso-invitation-tooltip");const n=window.Jetpack_SSOTooltip.tooltipString;function o(){t.appendChild(e),e.style.display="block"}function i(){t.ownerDocument.activeElement!==t&&t.removeChild(e)}e.innerHTML+=n,t.addEventListener("mouseenter",o),t.addEventListener("focus",o),t.addEventListener("mouseleave",i),t.addEventListener("blur",i)}),document.querySelectorAll(".jetpack-sso-invitation-tooltip-icon:not(.jetpack-sso-status-column)").forEach(function(n){n.addEventListener("mouseenter",t),n.addEventListener("focus",t),n.addEventListener("mouseleave",e),n.addEventListener("blur",e)})});
|
||||
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '53f1c19b5a564105c882');
|
||||
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '2a9e9767fedce3c596e7');
|
||||
|
||||
@ -1 +1 @@
|
||||
document.addEventListener("DOMContentLoaded",(function(){document.querySelectorAll(".jetpack-connection-tooltip").forEach((function(o){o.textContent=window.jetpackConnectionTooltips.columnTooltip}))}));
|
||||
document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll(".jetpack-connection-tooltip").forEach(function(o){o.textContent=window.jetpackConnectionTooltips.columnTooltip})});
|
||||
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => '2c644cc46566ed615c42');
|
||||
<?php return array('dependencies' => array(), 'version' => 'a25b171bd940e52c2b96');
|
||||
|
||||
@ -1 +1 @@
|
||||
!function(t,a){window.jpTracksAJAX=window.jpTracksAJAX||{};const c="dops:analytics"===localStorage.getItem("debug");window.jpTracksAJAX.record_ajax_event=function(n,e,r){const o={tracksNonce:a.jpTracksAJAX_nonce,action:"jetpack_tracks",tracksEventType:e,tracksEventName:n,tracksEventProp:r||!1};return t.ajax({type:"POST",url:a.ajaxurl,data:o,success:function(t){c&&console.log("AJAX tracks event recorded: ",o,t)}})},t(document).ready((function(){t("body").on("click",".jptracks a, a.jptracks",(function(a){const c=t(a.target),n=c.closest(".jptracks"),e=n.attr("data-jptracks-name");if(void 0===e)return;const r=n.attr("data-jptracks-prop")||!1,o=c.attr("href"),s=c.get(0).target;let i=null;o&&s&&"_self"!==s&&(i=window.open("",s),i.opener=null),a.preventDefault(),window.jpTracksAJAX.record_ajax_event(e,"click",r).always((function(){if(o&&!c.hasClass("thickbox")){if(i)return void(i.location=o);window.location=o}}))}))}))}(jQuery,jpTracksAJAX);
|
||||
!function(t,a){window.jpTracksAJAX=window.jpTracksAJAX||{};const c="dops:analytics"===localStorage.getItem("debug");window.jpTracksAJAX.record_ajax_event=function(n,e,r){const o={tracksNonce:a.jpTracksAJAX_nonce,action:"jetpack_tracks",tracksEventType:e,tracksEventName:n,tracksEventProp:r||!1};return t.ajax({type:"POST",url:a.ajaxurl,data:o,success:function(t){c&&console.log("AJAX tracks event recorded: ",o,t)}})},t(document).ready(function(){t("body").on("click",".jptracks a, a.jptracks",function(a){const c=t(a.target),n=c.closest(".jptracks"),e=n.attr("data-jptracks-name");if(void 0===e)return;const r=n.attr("data-jptracks-prop")||!1,o=c.attr("href"),s=c.get(0).target;let i=null;o&&s&&"_self"!==s&&(i=window.open("",s),i.opener=null),a.preventDefault(),window.jpTracksAJAX.record_ajax_event(e,"click",r).always(function(){if(o&&!c.hasClass("thickbox")){if(i)return void(i.location=o);window.location=o}})})})}(jQuery,jpTracksAJAX);
|
||||
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => 'a8b23de97e9658b5993f');
|
||||
<?php return array('dependencies' => array(), 'version' => 'a1795bfc061f496e47cf');
|
||||
|
||||
@ -1 +1 @@
|
||||
(()=>{var e={7961:e=>{let n;window._tkq=window._tkq||[];const t=console.error;const o={initialize:function(e,n){o.setUser(e,n),o.identifyUser()},mc:{bumpStat:function(e,n){const t=function(e,n){let t="";if("object"==typeof e)for(const n in e)t+="&x_"+encodeURIComponent(n)+"="+encodeURIComponent(e[n]);else t="&x_"+encodeURIComponent(e)+"="+encodeURIComponent(n);return t}(e,n);(new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?v=wpcom-no-pv"+t+"&t="+Math.random()}},tracks:{recordEvent:function(e,n){n=n||{},0===e.indexOf("jetpack_")?window._tkq.push(["recordEvent",e,n]):t('- Event name must be prefixed by "jetpack_"')},recordPageView:function(e){o.tracks.recordEvent("jetpack_page_view",{path:e})}},setUser:function(e,t){n={ID:e,username:t}},identifyUser:function(){n&&window._tkq.push(["identifyUser",n.ID,n.username])},clearedIdentity:function(){window._tkq.push(["clearIdentity"])}};e.exports=o}},n={};var t=function t(o){var r=n[o];if(void 0!==r)return r.exports;var i=n[o]={exports:{}};return e[o](i,i.exports,t),i.exports}(7961);window.analytics=t})();
|
||||
(()=>{var e={7961(e){let n;window._tkq=window._tkq||[];const t=console.error;const o={initialize:function(e,n){o.setUser(e,n),o.identifyUser()},mc:{bumpStat:function(e,n){const t=function(e,n){let t="";if("object"==typeof e)for(const n in e)t+="&x_"+encodeURIComponent(n)+"="+encodeURIComponent(e[n]);else t="&x_"+encodeURIComponent(e)+"="+encodeURIComponent(n);return t}(e,n);(new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?v=wpcom-no-pv"+t+"&t="+Math.random()}},tracks:{recordEvent:function(e,n){n=n||{},0===e.indexOf("jetpack_")?window._tkq.push(["recordEvent",e,n]):t('- Event name must be prefixed by "jetpack_"')},recordPageView:function(e){o.tracks.recordEvent("jetpack_page_view",{path:e})}},setUser:function(e,t){n={ID:e,username:t}},identifyUser:function(){n&&window._tkq.push(["identifyUser",n.ID,n.username])},clearedIdentity:function(){window._tkq.push(["clearIdentity"])}};e.exports=o}},n={};var t=function t(o){var r=n[o];if(void 0!==r)return r.exports;var i=n[o]={exports:{}};return e[o](i,i.exports,t),i.exports}(7961);window.analytics=t})();
|
||||
@ -9,6 +9,10 @@
|
||||
* @since-jetpack 7.7 Moved to the jetpack-connection package.
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* A Jetpack implementation of the WordPress core IXR client, capable of multiple calls in a single request.
|
||||
*/
|
||||
|
||||
@ -57,7 +57,7 @@ class Jetpack_Options {
|
||||
'site_icon_url', // (string) url to the full site icon
|
||||
'site_icon_id', // (int) Attachment id of the site icon file
|
||||
'dismissed_manage_banner', // (bool) Dismiss Jetpack manage banner allows the user to dismiss the banner permanently
|
||||
'unique_connection', // (array) A flag to determine a unique connection to wordpress.com two values "connected" and "disconnected" with values for how many times each has occured
|
||||
'unique_connection', // (array) A flag to determine a unique connection to wordpress.com two values "connected" and "disconnected" with values for how many times each has occurred
|
||||
'unique_registrations', // (integer) A counter of how many times the site was registered
|
||||
'protect_whitelist', // (array) IP Address for the Protect module to ignore
|
||||
'sync_error_idc', // (bool|array) false or array containing the site's home and siteurl at time of IDC error
|
||||
@ -193,6 +193,17 @@ class Jetpack_Options {
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_option( $name, $default = false ) {
|
||||
// Check if external storage should be used for this option
|
||||
if ( self::should_use_external_storage( $name ) ) {
|
||||
// Try external storage
|
||||
if ( class_exists( 'Automattic\Jetpack\Connection\External_Storage' ) ) {
|
||||
$external_value = \Automattic\Jetpack\Connection\External_Storage::get_value( $name );
|
||||
if ( null !== $external_value ) {
|
||||
return $external_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter Jetpack Options.
|
||||
* Can be useful in environments when Jetpack is running with a different setup
|
||||
@ -232,6 +243,34 @@ class Jetpack_Options {
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options that can be stored in external storage.
|
||||
*
|
||||
* @since 6.18.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $external_storage_allowlist = array( 'blog_token', 'id', 'master_user', 'user_tokens' );
|
||||
|
||||
/**
|
||||
* Determines if external storage should be used for a given option.
|
||||
* Simple allowlist check with global killswitch.
|
||||
*
|
||||
* @since 6.17.0
|
||||
*
|
||||
* @param string $name Option name, _without_ `jetpack_%` prefix.
|
||||
* @return bool True if external storage should be checked for this option.
|
||||
*/
|
||||
private static function should_use_external_storage( $name ) {
|
||||
// Check allowlist and global killswitch
|
||||
if ( ! in_array( $name, self::$external_storage_allowlist, true ) ||
|
||||
( defined( 'JETPACK_EXTERNAL_STORAGE_DISABLED' ) && constant( 'JETPACK_EXTERNAL_STORAGE_DISABLED' ) ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested option, and ensures it's autoloaded in the future.
|
||||
* This does _not_ adjust the prefix in any way (does not prefix jetpack_%)
|
||||
@ -296,8 +335,8 @@ class Jetpack_Options {
|
||||
* @since 1.1.2
|
||||
* @since-jetpack 3.0.0
|
||||
*
|
||||
* @param str $name The name of the option being updated.
|
||||
* @param mixed $value The new value of the option.
|
||||
* @param string $name The name of the option being updated.
|
||||
* @param mixed $value The new value of the option.
|
||||
*/
|
||||
do_action( 'pre_update_jetpack_option_' . $name, $name, $value );
|
||||
if ( self::is_valid( $name, 'non_compact' ) ) {
|
||||
|
||||
@ -46,8 +46,8 @@ class Jetpack_Signature {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $access_token Access token.
|
||||
* @param int $time_diff Timezone difference (in seconds).
|
||||
* @param string $access_token Access token.
|
||||
* @param int $time_diff Timezone difference (in seconds).
|
||||
*/
|
||||
public function __construct( $access_token, $time_diff = 0 ) {
|
||||
$secret = explode( '.', $access_token );
|
||||
@ -168,7 +168,10 @@ class Jetpack_Signature {
|
||||
if ( is_array( $body ) ) {
|
||||
if ( $body !== array() ) {
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode
|
||||
$body = json_encode( $body );
|
||||
$body = json_encode(
|
||||
$body,
|
||||
0 // phpcs:ignore Jetpack.Functions.JsonEncodeFlags.ZeroFound -- No `json_encode()` flags because this needs to match whatever is calculating the hash on the other end.
|
||||
);
|
||||
|
||||
} else {
|
||||
$body = '';
|
||||
@ -219,7 +222,7 @@ class Jetpack_Signature {
|
||||
return new WP_Error( 'unknown_scheme_port', "The scheme's port is unknown", compact( 'signature_details' ) );
|
||||
}
|
||||
|
||||
if ( ! ctype_digit( "$timestamp" ) || 10 < strlen( $timestamp ) ) { // If Jetpack is around in 275 years, you can blame mdawaffe for the bug.
|
||||
if ( ! ctype_digit( "$timestamp" ) || 10 < strlen( (string) $timestamp ) ) { // If Jetpack is around in 275 years, you can blame mdawaffe for the bug.
|
||||
return new WP_Error( 'invalid_signature', sprintf( 'The required "%s" parameter is malformed.', 'timestamp' ), compact( 'signature_details' ) );
|
||||
}
|
||||
|
||||
|
||||
@ -304,7 +304,8 @@ class Jetpack_XMLRPC_Server {
|
||||
$nonce = sanitize_text_field( $request['nonce'] );
|
||||
unset( $request['nonce'] );
|
||||
|
||||
$api_url = $this->connection->api_url( 'partner_provision_nonce_check' );
|
||||
$api_url = $this->connection->api_url( 'partner_provision_nonce_check' );
|
||||
// @phan-suppress-next-line PhanAccessMethodInternal -- Phan is correct, but the usage is intentional.
|
||||
$response = Client::_wp_remote_request(
|
||||
esc_url_raw( add_query_arg( 'nonce', $nonce, $api_url ) ),
|
||||
array( 'method' => 'GET' ),
|
||||
@ -715,11 +716,12 @@ class Jetpack_XMLRPC_Server {
|
||||
'md5',
|
||||
json_encode( // phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode
|
||||
(object) array(
|
||||
'client_id' => (int) $client_id,
|
||||
'user_id' => (int) $user_id,
|
||||
'nonce' => (string) $nonce,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'nonce' => $nonce,
|
||||
'code' => (string) $api_user_code,
|
||||
)
|
||||
),
|
||||
0 // phpcs:ignore Jetpack.Functions.JsonEncodeFlags.ZeroFound -- No `json_encode()` flags because this needs to match whatever is calculating the hash on the other end.
|
||||
),
|
||||
$jetpack_token->secret
|
||||
);
|
||||
|
||||
@ -164,7 +164,10 @@ class Client {
|
||||
// We cast this to a new variable, because the array form of $body needs to be
|
||||
// maintained so it can be passed into the request later on in the code.
|
||||
if ( array() !== $body_to_hash ) {
|
||||
$body_to_hash = wp_json_encode( self::_stringify_data( $body_to_hash ) );
|
||||
$body_to_hash = wp_json_encode(
|
||||
self::_stringify_data( $body_to_hash ),
|
||||
0 // phpcs:ignore Jetpack.Functions.JsonEncodeFlags.ZeroFound -- No `json_encode()` flags because this needs to match whatever is calculating the hash on the other end.
|
||||
);
|
||||
} else {
|
||||
$body_to_hash = '';
|
||||
}
|
||||
@ -417,7 +420,7 @@ class Client {
|
||||
* @param string $path REST API path.
|
||||
* @param string $version REST API version. Default is `2`.
|
||||
* @param array $args Arguments to {@see WP_Http}. Default is `array()`.
|
||||
* @param null|string|array $body Body passed to {@see WP_Http}. Default is `null`.
|
||||
* @param null|string|array $body Body passed to {@see WP_Http}. Default is `null`.
|
||||
* @param string $base_api_path REST API root. Default is `wpcom`.
|
||||
*
|
||||
* @return array|WP_Error $response Response data, else {@see WP_Error} on failure.
|
||||
@ -438,7 +441,7 @@ class Client {
|
||||
}
|
||||
|
||||
if ( isset( $body ) && ! is_string( $body ) ) {
|
||||
$body = wp_json_encode( $body );
|
||||
$body = wp_json_encode( $body, JSON_UNESCAPED_SLASHES );
|
||||
}
|
||||
|
||||
return self::remote_request( $args, $body );
|
||||
|
||||
@ -12,6 +12,8 @@ use Automattic\Jetpack\Tracking;
|
||||
|
||||
/**
|
||||
* Admin connection notices.
|
||||
*
|
||||
* @phan-constructor-used-for-side-effects
|
||||
*/
|
||||
class Connection_Notice {
|
||||
|
||||
@ -167,11 +169,11 @@ class Connection_Notice {
|
||||
}
|
||||
|
||||
fetch(
|
||||
<?php echo wp_json_encode( esc_url_raw( get_rest_url() . 'jetpack/v4/connection/owner' ), JSON_HEX_TAG | JSON_HEX_AMP ); ?>,
|
||||
<?php echo wp_json_encode( esc_url_raw( get_rest_url() . 'jetpack/v4/connection/owner' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-WP-Nonce': <?php echo wp_json_encode( wp_create_nonce( 'wp_rest' ), JSON_HEX_TAG | JSON_HEX_AMP ); ?>,
|
||||
'X-WP-Nonce': <?php echo wp_json_encode( wp_create_nonce( 'wp_rest' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>,
|
||||
},
|
||||
body: new URLSearchParams( new FormData( this ) ),
|
||||
}
|
||||
@ -180,7 +182,7 @@ class Connection_Notice {
|
||||
.then( data => {
|
||||
if ( data.hasOwnProperty( 'code' ) && data.code === 'success' ) {
|
||||
// Owner successfully changed.
|
||||
results.innerHTML = <?php echo wp_json_encode( esc_html__( 'Success!', 'jetpack-connection' ), JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
|
||||
results.innerHTML = <?php echo wp_json_encode( esc_html__( 'Success!', 'jetpack-connection' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
|
||||
setTimeout(function () {
|
||||
document.getElementById( 'jetpack-notice-switch-connection-owner' ).style.display = 'none';
|
||||
}, 1000);
|
||||
|
||||
@ -10,17 +10,20 @@ namespace Automattic\Jetpack\Connection;
|
||||
/**
|
||||
* The Jetpack Connection Errors that handles errors
|
||||
*
|
||||
* This class handles the following workflow:
|
||||
* This class handles the following workflow for incoming XML-RPC and REST API requests:
|
||||
*
|
||||
* 1. A XML-RCP request with an invalid signature triggers a error
|
||||
* 1. An incoming XML-RPC or REST API request with an invalid signature triggers an error
|
||||
* 2. Applies a gate to only process each error code once an hour to avoid overflow
|
||||
* 3. It stores the error on the database, but we don't know yet if this is a valid error, because
|
||||
* we can't confirm it came from WP.com.
|
||||
* 4. It encrypts the error details and send it to thw wp.com server
|
||||
* 4. It encrypts the error details and sends it to the wp.com server
|
||||
* 5. wp.com checks it and, if valid, sends a new request back to this site using the verify_xml_rpc_error REST endpoint
|
||||
* 6. This endpoint add this error to the Verified errors in the database
|
||||
* 6. This endpoint adds this error to the Verified errors in the database
|
||||
* 7. Triggers a workflow depending on the error (display user an error message, do some self healing, etc.)
|
||||
*
|
||||
* Note: This class only handles authentication/signature errors from incoming requests to this site.
|
||||
* Outgoing request signing issues (when this site makes requests to WP.com) are not handled here.
|
||||
*
|
||||
* Errors are stored in the database as options in the following format:
|
||||
*
|
||||
* [
|
||||
@ -33,11 +36,26 @@ namespace Automattic\Jetpack\Connection;
|
||||
*
|
||||
* For each error code we store a maximum of 5 errors for 5 different user ids.
|
||||
*
|
||||
* An user ID can be
|
||||
* A user ID can be:
|
||||
* * 0 for blog tokens
|
||||
* * positive integer for user tokens
|
||||
* * 'invalid' for malformed tokens
|
||||
*
|
||||
* Example error structure:
|
||||
* [
|
||||
* 'invalid_token' => [
|
||||
* '123' => [
|
||||
* 'error_code' => 'invalid_token',
|
||||
* 'user_id' => '123',
|
||||
* 'error_message' => 'The token is invalid',
|
||||
* 'error_data' => ['action' => 'reconnect'],
|
||||
* 'timestamp' => 1234567890,
|
||||
* 'nonce' => 'abc123def',
|
||||
* 'error_type' => 'xmlrpc'
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* @since 1.14.2
|
||||
*/
|
||||
class Error_Handler {
|
||||
@ -76,14 +94,6 @@ class Error_Handler {
|
||||
*/
|
||||
const ERROR_LIFE_TIME = DAY_IN_SECONDS;
|
||||
|
||||
/**
|
||||
* The error code for event tracking purposes.
|
||||
* If there are many, only the first error code will be tracked.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $error_code;
|
||||
|
||||
/**
|
||||
* List of known errors. Only error codes in this list will be handled
|
||||
*
|
||||
@ -127,7 +137,16 @@ class Error_Handler {
|
||||
public static $instance = null;
|
||||
|
||||
/**
|
||||
* Initialize instance, hookds and load verified errors handlers
|
||||
* Cached displayable errors to avoid duplicate processing
|
||||
*
|
||||
* @since 6.13.10
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
private $cached_displayable_errors = null;
|
||||
|
||||
/**
|
||||
* Initialize instance, hooks and load verified errors handlers
|
||||
*
|
||||
* @since 1.14.2
|
||||
*/
|
||||
@ -149,38 +168,213 @@ class Error_Handler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of verified errors and act upon them
|
||||
* Gets displayable errors with predefined structure and optional filtering.
|
||||
*
|
||||
* @since 1.14.2
|
||||
* This method returns a hierarchical array of errors (error_code => user_id => error_details)
|
||||
* that can be safely displayed in My Jetpack and other UI components. It includes
|
||||
* predefined error messages and actions, with optional filtering for specific sites.
|
||||
* Only processes a limited set of error codes that are meant to be displayed to users.
|
||||
*
|
||||
* @return void
|
||||
* @since 6.13.10
|
||||
*
|
||||
* @return array Array of displayable errors with hierarchical structure.
|
||||
* Example:
|
||||
* [
|
||||
* 'invalid_token' => [
|
||||
* '123' => [
|
||||
* 'error_code' => 'invalid_token',
|
||||
* 'user_id' => '123',
|
||||
* 'error_message' => 'Your connection with WordPress.com seems to be broken...',
|
||||
* 'error_data' => ['action' => 'reconnect'],
|
||||
* 'timestamp' => 1234567890,
|
||||
* 'nonce' => 'abc123def',
|
||||
* 'error_type' => 'xmlrpc'
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
*/
|
||||
public function handle_verified_errors() {
|
||||
$verified_errors = $this->get_verified_errors();
|
||||
foreach ( array_keys( $verified_errors ) as $error_code ) {
|
||||
switch ( $error_code ) {
|
||||
case 'malformed_token':
|
||||
case 'token_malformed':
|
||||
case 'no_possible_tokens':
|
||||
case 'no_valid_user_token':
|
||||
case 'no_valid_blog_token':
|
||||
case 'unknown_token':
|
||||
case 'could_not_sign':
|
||||
case 'invalid_token':
|
||||
case 'token_mismatch':
|
||||
case 'invalid_signature':
|
||||
case 'signature_mismatch':
|
||||
case 'no_user_tokens':
|
||||
case 'no_token_for_user':
|
||||
case 'invalid_connection_owner':
|
||||
add_action( 'admin_notices', array( $this, 'generic_admin_notice_error' ) );
|
||||
add_action( 'react_connection_errors_initial_state', array( $this, 'jetpack_react_dashboard_error' ) );
|
||||
$this->error_code = $error_code;
|
||||
public function get_displayable_errors() {
|
||||
// Check if we have cached result AND no filters are applied
|
||||
if ( $this->cached_displayable_errors !== null && ! $this->has_external_filters() ) {
|
||||
return $this->cached_displayable_errors;
|
||||
}
|
||||
|
||||
// Since we are only generically handling errors, we don't need to trigger error messages for each one of them.
|
||||
break 2;
|
||||
$verified_errors = $this->get_verified_errors();
|
||||
$displayable_errors = array();
|
||||
|
||||
// Only process error codes that are meant to be displayed to users
|
||||
$displayable_error_codes = array(
|
||||
'malformed_token',
|
||||
'token_malformed',
|
||||
'no_possible_tokens',
|
||||
'no_valid_user_token',
|
||||
'no_valid_blog_token',
|
||||
'unknown_token',
|
||||
'could_not_sign',
|
||||
'invalid_token',
|
||||
'token_mismatch',
|
||||
'invalid_signature',
|
||||
'signature_mismatch',
|
||||
'no_user_tokens',
|
||||
'no_token_for_user',
|
||||
'invalid_connection_owner',
|
||||
);
|
||||
|
||||
foreach ( $verified_errors as $error_code => $users ) {
|
||||
// Skip error codes that are not meant to be displayed
|
||||
if ( ! in_array( $error_code, $displayable_error_codes, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$displayable_errors[ $error_code ] = array();
|
||||
|
||||
foreach ( $users as $user_id => $error ) {
|
||||
// Override other error messages with default display message
|
||||
$displayable_errors[ $error_code ][ $user_id ] = array_merge(
|
||||
$error,
|
||||
array(
|
||||
'error_message' => __( "Your connection with WordPress.com seems to be broken. If you're experiencing issues, please try reconnecting.", 'jetpack-connection' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter displayable connection errors to allow customization of error messages and actions.
|
||||
*
|
||||
* This filter allows sites to customize how connection errors are displayed,
|
||||
* including modifying error messages, actions, and data. Access to this filter
|
||||
* is controlled by should_allow_error_filtering().
|
||||
*
|
||||
* @since 6.12.0
|
||||
*
|
||||
* @param array $displayable_errors Array of displayable errors with hierarchical structure.
|
||||
* @param array $verified_errors Array of raw verified errors from the database.
|
||||
*/
|
||||
if ( $this->should_allow_error_filtering() ) {
|
||||
$displayable_errors = apply_filters( 'jetpack_connection_get_verified_errors', $displayable_errors, $verified_errors );
|
||||
}
|
||||
|
||||
// Only cache if no external filters are applied
|
||||
if ( ! $this->has_external_filters() ) {
|
||||
$this->cached_displayable_errors = $displayable_errors;
|
||||
}
|
||||
|
||||
return $displayable_errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up hooks for displaying verified errors on admin pages.
|
||||
*
|
||||
* This method is hooked into 'admin_init'. It retrieves displayable errors
|
||||
* and, if any exist, sets up the necessary action and filter hooks to display
|
||||
* them in admin notices and the React dashboard.
|
||||
*
|
||||
* @since 1.14.2
|
||||
*/
|
||||
public function handle_verified_errors() {
|
||||
$displayable_errors = $this->get_displayable_errors();
|
||||
|
||||
// If there are any displayable errors, set up the hooks for displaying them in React dashboard and admin notices.
|
||||
if ( ! empty( $displayable_errors ) ) {
|
||||
add_action( 'admin_notices', array( $this, 'generic_admin_notice_error' ) );
|
||||
add_filter( 'react_connection_errors_initial_state', array( $this, 'jetpack_react_dashboard_error' ), 10, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether error filtering should be allowed.
|
||||
*
|
||||
* This method controls access to the jetpack_connection_displayable_errors filter.
|
||||
* Currently, only WoA sites are allowed to use this filter.
|
||||
*
|
||||
* @since 6.13.10
|
||||
*
|
||||
* @return bool True if error filtering should be allowed, false otherwise.
|
||||
*/
|
||||
protected function should_allow_error_filtering() {
|
||||
$host = new \Automattic\Jetpack\Status\Host();
|
||||
if ( $host->is_woa_site() || $host->is_vip_site() || $host->is_newspack_site() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides displayable connection errors for the React dashboard in a flat array format.
|
||||
*
|
||||
* This method transforms the hierarchical displayable_errors structure into the flat format
|
||||
* expected by the React dashboard. It's used as a filter for 'react_connection_errors_initial_state'.
|
||||
* Returns only the first error to avoid overwhelming the user with multiple error messages.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*
|
||||
* @param array $errors Existing errors from other filters (unused but required for filter signature).
|
||||
* @return array Array containing only the first displayable error for the React dashboard.
|
||||
* Example:
|
||||
* [
|
||||
* [
|
||||
* 'code' => 'connection_error',
|
||||
* 'message' => 'Your connection with WordPress.com seems to be broken...',
|
||||
* 'action' => 'reconnect',
|
||||
* 'data' => [
|
||||
* 'api_error_code' => 'invalid_token',
|
||||
* 'action' => 'reconnect'
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
*/
|
||||
public function jetpack_react_dashboard_error( $errors ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
$displayable_errors = $this->get_displayable_errors();
|
||||
|
||||
// Get the first error only
|
||||
$first_error_code = array_key_first( $displayable_errors );
|
||||
if ( ! $first_error_code ) {
|
||||
return array(); // No errors
|
||||
}
|
||||
|
||||
$first_user_errors = $displayable_errors[ $first_error_code ];
|
||||
if ( ! is_array( $first_user_errors ) || empty( $first_user_errors ) ) {
|
||||
return array(); // Invalid error structure
|
||||
}
|
||||
|
||||
$first_error = reset( $first_user_errors );
|
||||
|
||||
// Validate error structure
|
||||
if ( ! is_array( $first_error ) || ! isset( $first_error['error_message'] ) ) {
|
||||
return array(); // Invalid error structure
|
||||
}
|
||||
|
||||
// Determine the action - use the one from error_data if available, otherwise default to 'reconnect'
|
||||
$action = 'reconnect'; // Default action for connection errors
|
||||
if ( isset( $first_error['error_data']['action'] ) && is_string( $first_error['error_data']['action'] ) ) {
|
||||
$action = $first_error['error_data']['action'];
|
||||
}
|
||||
|
||||
// Safely merge error data, ensuring we don't overwrite critical fields
|
||||
$error_data = isset( $first_error['error_data'] ) && is_array( $first_error['error_data'] ) ? $first_error['error_data'] : array();
|
||||
|
||||
// Build the data array with safe merging
|
||||
$dashboard_data = array( 'api_error_code' => $first_error_code );
|
||||
|
||||
// Add error_data fields, but be careful not to overwrite api_error_code
|
||||
foreach ( $error_data as $key => $value ) {
|
||||
if ( 'api_error_code' !== $key ) {
|
||||
$dashboard_data[ $key ] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$dashboard_error = array(
|
||||
array(
|
||||
'code' => 'connection_error',
|
||||
'message' => $first_error['error_message'],
|
||||
'action' => $action,
|
||||
'data' => $dashboard_data,
|
||||
),
|
||||
);
|
||||
|
||||
return $dashboard_error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -208,7 +402,7 @@ class Error_Handler {
|
||||
* @since 1.14.2
|
||||
*/
|
||||
public function report_error( \WP_Error $error, $force = false, $skip_wpcom_verification = false ) {
|
||||
if ( in_array( $error->get_error_code(), $this->known_errors, true ) && $this->should_report_error( $error ) || $force ) {
|
||||
if ( in_array( $error->get_error_code(), $this->known_errors, true ) && ( $this->should_report_error( $error ) || $force ) ) {
|
||||
$stored_error = $this->store_error( $error );
|
||||
if ( $stored_error ) {
|
||||
$skip_wpcom_verification ? $this->verify_error( $stored_error ) : $this->send_error_to_wpcom( $stored_error );
|
||||
@ -227,7 +421,7 @@ class Error_Handler {
|
||||
* @return boolean $should_report True if gate is open and the error should be reported.
|
||||
*/
|
||||
public function should_report_error( \WP_Error $error ) {
|
||||
if ( defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG ) {
|
||||
if ( defined( '\\JETPACK_DEV_DEBUG' ) && constant( '\\JETPACK_DEV_DEBUG' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -294,6 +488,106 @@ class Error_Handler {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds action error data for generic JavaScript components.
|
||||
*
|
||||
* This helper method creates standardized error_data arrays that work with the generic
|
||||
* JavaScript error handling components. External plugins (like wpcomsh) can use this
|
||||
* to ensure their error structures are compatible.
|
||||
*
|
||||
* @since 6.16.0
|
||||
*
|
||||
* @param array $args Action configuration arguments - only non-empty values will be included.
|
||||
* @return array Standardized error_data array for JavaScript components.
|
||||
*/
|
||||
public function build_action_error_data( array $args = array() ) {
|
||||
// Set default values for variants
|
||||
$args = wp_parse_args(
|
||||
$args,
|
||||
array(
|
||||
'action_variant' => 'primary',
|
||||
'secondary_action_variant' => 'secondary',
|
||||
)
|
||||
);
|
||||
|
||||
// Start with core data
|
||||
$error_data = array(
|
||||
'blog_id' => \Jetpack_Options::get_option( 'id' ),
|
||||
);
|
||||
|
||||
// Validate variant values
|
||||
$valid_variants = array( 'primary', 'secondary' );
|
||||
if ( ! in_array( $args['action_variant'], $valid_variants, true ) ) {
|
||||
$args['action_variant'] = 'primary';
|
||||
}
|
||||
if ( ! in_array( $args['secondary_action_variant'], $valid_variants, true ) ) {
|
||||
$args['secondary_action_variant'] = 'secondary';
|
||||
}
|
||||
|
||||
// Merge extra_data first, then regular args (so args take precedence)
|
||||
if ( ! empty( $args['extra_data'] ) && is_array( $args['extra_data'] ) ) {
|
||||
$error_data = array_merge( $error_data, $args['extra_data'] );
|
||||
unset( $args['extra_data'] ); // Remove from args to avoid duplication
|
||||
}
|
||||
|
||||
// Filter out empty values and merge with error_data
|
||||
$filtered_args = array_filter(
|
||||
$args,
|
||||
function ( $value ) {
|
||||
return ! empty( $value );
|
||||
}
|
||||
);
|
||||
|
||||
return array_merge( $error_data, $filtered_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a standardized error array for the connection error system.
|
||||
*
|
||||
* This method creates a consistent error array structure that can be used
|
||||
* by both internal error handling and external plugins/customizations.
|
||||
*
|
||||
* @since 1.14.2
|
||||
*
|
||||
* @param string $error_code The error code identifier.
|
||||
* @param string $error_message The human-readable error message.
|
||||
* @param array $error_data Additional error data (optional).
|
||||
* @param string $user_id The user ID associated with the error (optional).
|
||||
* @param string $error_type The type of error (optional).
|
||||
* @return array|false The standardized error array or false on failure.
|
||||
* Example successful return:
|
||||
* [
|
||||
* 'error_code' => 'invalid_token',
|
||||
* 'user_id' => '123',
|
||||
* 'error_message' => 'The token is invalid',
|
||||
* 'error_data' => ['action' => 'reconnect'],
|
||||
* 'timestamp' => 1234567890,
|
||||
* 'nonce' => 'abc123def',
|
||||
* 'error_type' => 'xmlrpc'
|
||||
* ]
|
||||
*/
|
||||
public function build_error_array( string $error_code, string $error_message, array $error_data = array(), $user_id = '0', string $error_type = '' ) {
|
||||
// Validate required parameters
|
||||
if ( empty( $error_code ) || empty( $error_message ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate user_id is a string or integer
|
||||
if ( ! is_string( $user_id ) && ! is_int( $user_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array(
|
||||
'error_code' => $error_code,
|
||||
'user_id' => $user_id,
|
||||
'error_message' => $error_message,
|
||||
'error_data' => $error_data,
|
||||
'timestamp' => time(),
|
||||
'nonce' => wp_generate_password( 10, false ),
|
||||
'error_type' => $error_type,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a WP_Error object in the array representation we store in the database
|
||||
*
|
||||
@ -318,17 +612,13 @@ class Error_Handler {
|
||||
|
||||
$user_id = $this->get_user_id_from_token( $signature_details['token'] );
|
||||
|
||||
$error_array = array(
|
||||
'error_code' => $error->get_error_code(),
|
||||
'user_id' => $user_id,
|
||||
'error_message' => $error->get_error_message(),
|
||||
'error_data' => $signature_details,
|
||||
'timestamp' => time(),
|
||||
'nonce' => wp_generate_password( 10, false ),
|
||||
'error_type' => empty( $data['error_type'] ) ? '' : $data['error_type'],
|
||||
return $this->build_error_array(
|
||||
$error->get_error_code(),
|
||||
$error->get_error_message(),
|
||||
$signature_details,
|
||||
$user_id,
|
||||
empty( $data['error_type'] ) ? '' : $data['error_type']
|
||||
);
|
||||
|
||||
return $error_array;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,7 +663,7 @@ class Error_Handler {
|
||||
try {
|
||||
// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
||||
$encrypted_data = base64_encode( sodium_crypto_box_seal( wp_json_encode( $data ), base64_decode( JETPACK__ERRORS_PUBLIC_KEY ) ) );
|
||||
$encrypted_data = base64_encode( sodium_crypto_box_seal( wp_json_encode( $data, JSON_UNESCAPED_SLASHES ), base64_decode( JETPACK__ERRORS_PUBLIC_KEY ) ) );
|
||||
// phpcs:enable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
// phpcs:enable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
||||
} catch ( \SodiumException $e ) {
|
||||
@ -427,14 +717,18 @@ class Error_Handler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the verified errors stored in the database
|
||||
* Gets the verified errors stored in the database.
|
||||
*
|
||||
* This method retrieves only the errors that are actually stored in the database,
|
||||
* without applying any filters that might inject additional errors. This is used
|
||||
* internally by methods that need to modify and store the verified errors back
|
||||
* to the database to prevent accidentally persisting filtered/injected errors.
|
||||
*
|
||||
* @since 1.14.2
|
||||
*
|
||||
* @return array $errors
|
||||
*/
|
||||
public function get_verified_errors() {
|
||||
|
||||
$verified_errors = get_option( self::STORED_VERIFIED_ERRORS_OPTION );
|
||||
|
||||
if ( ! is_array( $verified_errors ) ) {
|
||||
@ -451,7 +745,7 @@ class Error_Handler {
|
||||
*
|
||||
* This method is called by get_stored_errors and get_verified errors and filters their result
|
||||
* Whenever a new error is stored to the database or verified, this will be triggered and the
|
||||
* expired error will be permantently removed from the database
|
||||
* expired error will be permanently removed from the database
|
||||
*
|
||||
* @since 1.14.2
|
||||
*
|
||||
@ -461,7 +755,7 @@ class Error_Handler {
|
||||
private function garbage_collector( $errors ) {
|
||||
foreach ( $errors as $error_code => $users ) {
|
||||
foreach ( $users as $user_id => $error ) {
|
||||
if ( self::ERROR_LIFE_TIME < time() - (int) $error['timestamp'] ) {
|
||||
if ( empty( $error['timestamp'] ) || self::ERROR_LIFE_TIME < time() - (int) $error['timestamp'] ) {
|
||||
unset( $errors[ $error_code ][ $user_id ] );
|
||||
}
|
||||
}
|
||||
@ -486,6 +780,9 @@ class Error_Handler {
|
||||
public function delete_all_errors() {
|
||||
$this->delete_stored_errors();
|
||||
$this->delete_verified_errors();
|
||||
|
||||
// Invalidate cache since we deleted all errors
|
||||
$this->invalidate_displayable_errors_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -527,6 +824,9 @@ class Error_Handler {
|
||||
delete_option( static::STORED_VERIFIED_ERRORS_OPTION );
|
||||
}
|
||||
}
|
||||
|
||||
// Invalidate cache since we may have deleted verified errors
|
||||
$this->invalidate_displayable_errors_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -609,10 +909,13 @@ class Error_Handler {
|
||||
$verified_errors[ $error_code ][ $user_id ] = $error;
|
||||
|
||||
update_option( self::STORED_VERIFIED_ERRORS_OPTION, $verified_errors );
|
||||
|
||||
// Invalidate cache since we added a new verified error
|
||||
$this->invalidate_displayable_errors_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register REST API end point for error hanlding.
|
||||
* Register REST API end point for error handling.
|
||||
*
|
||||
* @since 1.14.2
|
||||
*
|
||||
@ -686,7 +989,7 @@ class Error_Handler {
|
||||
* @param string $message The error message.
|
||||
* @param array $errors The array of errors. See Automattic\Jetpack\Connection\Error_Handler for details on the array structure.
|
||||
*/
|
||||
$message = apply_filters( 'jetpack_connection_error_notice_message', '', $this->get_verified_errors() );
|
||||
$message = apply_filters( 'jetpack_connection_error_notice_message', '', $this->get_displayable_errors() );
|
||||
|
||||
/**
|
||||
* Fires inside the admin_notices hook just before displaying the error message for a broken connection.
|
||||
@ -697,7 +1000,7 @@ class Error_Handler {
|
||||
*
|
||||
* @param array $errors The array of errors. See Automattic\Jetpack\Connection\Error_Handler for details on the array structure.
|
||||
*/
|
||||
do_action( 'jetpack_connection_error_notice', $this->get_verified_errors() );
|
||||
do_action( 'jetpack_connection_error_notice', $this->get_displayable_errors() );
|
||||
|
||||
if ( empty( $message ) ) {
|
||||
return;
|
||||
@ -714,24 +1017,6 @@ class Error_Handler {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the error message to the Jetpack React Dashboard
|
||||
*
|
||||
* @since 8.9.0
|
||||
*
|
||||
* @param array $errors The array of errors. See Automattic\Jetpack\Connection\Error_Handler for details on the array structure.
|
||||
* @return array
|
||||
*/
|
||||
public function jetpack_react_dashboard_error( $errors ) {
|
||||
$errors[] = array(
|
||||
'code' => 'connection_error',
|
||||
'message' => __( 'Your connection with WordPress.com seems to be broken. If you\'re experiencing issues, please try reconnecting.', 'jetpack-connection' ),
|
||||
'action' => 'reconnect',
|
||||
'data' => array( 'api_error_code' => $this->error_code ),
|
||||
);
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check REST API response for errors, and report them to WP.com if needed.
|
||||
*
|
||||
@ -777,4 +1062,27 @@ class Error_Handler {
|
||||
|
||||
$this->report_error( $error, false, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether external filters are applied to the get_displayable_errors method.
|
||||
*
|
||||
* @since 6.13.10
|
||||
*
|
||||
* @return bool True if external filters are applied, false otherwise.
|
||||
*/
|
||||
private function has_external_filters() {
|
||||
return has_filter( 'jetpack_connection_get_verified_errors' ) &&
|
||||
$this->should_allow_error_filtering();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the cached displayable errors
|
||||
*
|
||||
* @since 6.13.10
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function invalidate_displayable_errors_cache() {
|
||||
$this->cached_displayable_errors = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,280 @@
|
||||
<?php
|
||||
/**
|
||||
* External Storage utilities for Jetpack Connection.
|
||||
*
|
||||
* Provides centralized logic for external storage implementations
|
||||
* across different environments (WoA, VIP, other).
|
||||
*
|
||||
* Usage Example:
|
||||
*
|
||||
* // 1. Create a storage provider class implementing the interface:
|
||||
* class My_Storage_Provider implements Storage_Provider_Interface {
|
||||
* public function is_available() { return true; }
|
||||
* public function should_handle( $option_name ) {
|
||||
* return in_array( $option_name, array( 'blog_token', 'id' ), true );
|
||||
* }
|
||||
* public function get( $option_name ) {
|
||||
* // Return value from your external storage or null
|
||||
* }
|
||||
* public function get_environment_id() { return 'my_env'; }
|
||||
* }
|
||||
*
|
||||
* // 2. Register the provider:
|
||||
* if ( class_exists( 'Automattic\Jetpack\Connection\External_Storage' ) ) {
|
||||
* \Automattic\Jetpack\Connection\External_Storage::register_provider( new My_Storage_Provider() );
|
||||
* }
|
||||
*
|
||||
* // 3. External storage is now automatically used by Jetpack_Options::get_option()
|
||||
*
|
||||
* @package automattic/jetpack-connection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Connection;
|
||||
|
||||
require_once __DIR__ . '/interface-storage-provider.php';
|
||||
|
||||
/**
|
||||
* External Storage utilities class.
|
||||
*
|
||||
* @since 6.18.0
|
||||
*/
|
||||
class External_Storage {
|
||||
|
||||
/**
|
||||
* Registered storage provider.
|
||||
*
|
||||
* @since 6.18.0
|
||||
*
|
||||
* @var Storage_Provider_Interface|null
|
||||
*/
|
||||
private static $provider = null;
|
||||
|
||||
/**
|
||||
* Static cache to prevent logging same event multiple times in single request.
|
||||
*
|
||||
* @since 7.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $logged_events = array();
|
||||
|
||||
/**
|
||||
* Maximum delay threshold for empty state reporting (in seconds).
|
||||
* This also determines the transient expiry for tracking first empty state.
|
||||
* Provider custom thresholds must not exceed this value.
|
||||
*
|
||||
* @since 7.0.0
|
||||
*/
|
||||
private const EMPTY_STATE_TRANSIENT_EXPIRY = 15 * MINUTE_IN_SECONDS;
|
||||
|
||||
/**
|
||||
* Register a storage provider for external storage.
|
||||
*
|
||||
* @since 6.18.0
|
||||
*
|
||||
* @param Storage_Provider_Interface $provider Storage provider implementing the interface.
|
||||
* @return bool True if provider was registered successfully, false otherwise.
|
||||
*/
|
||||
public static function register_provider( Storage_Provider_Interface $provider ) {
|
||||
self::$provider = $provider;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value from external storage provider.
|
||||
*
|
||||
* Returns null if no provider is registered or if the provider can't provide the value (triggers database fallback).
|
||||
*
|
||||
* @since 6.18.0
|
||||
*
|
||||
* @param string $key The key to retrieve.
|
||||
* @return mixed The value from external storage, or null for database fallback.
|
||||
*/
|
||||
public static function get_value( $key ) {
|
||||
$provider = self::$provider;
|
||||
|
||||
// Check if we have a registered provider
|
||||
if ( null === $provider ) {
|
||||
return null; // No provider registered, use database
|
||||
}
|
||||
|
||||
$environment = $provider->get_environment_id();
|
||||
|
||||
// Check if provider is available in current environment
|
||||
if ( ! $provider->is_available() ) {
|
||||
self::log_event( 'unavailable', $key, 'External storage not available', $environment );
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if provider should handle this option
|
||||
if ( ! $provider->should_handle( $key ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to get value from the provider
|
||||
try {
|
||||
$value = $provider->get( $key );
|
||||
|
||||
// Check if we got a valid value
|
||||
if ( null !== $value && false !== $value && '' !== $value && 0 !== $value ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Empty value - log it
|
||||
self::log_event( 'empty', $key, '', $environment );
|
||||
|
||||
} catch ( \Exception $e ) {
|
||||
// Provider threw an exception
|
||||
self::log_event( 'error', $key, $e->getMessage(), $environment );
|
||||
}
|
||||
|
||||
// Provider couldn't provide value, return null for database fallback
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log events if WP_DEBUG is enabled and delegate to provider for error reporting.
|
||||
* Includes rate limiting to prevent log spam from noisy events.
|
||||
*
|
||||
* Storage providers can optionally implement handle_error_event() method to receive
|
||||
* notifications about storage errors and empty states for their own error reporting.
|
||||
*
|
||||
* @since 6.18.0
|
||||
*
|
||||
* @param string $event_type The event type (error, empty, unavailable).
|
||||
* @param string $key The key that triggered the event.
|
||||
* @param string $details Additional details about the event.
|
||||
* @param string $environment The environment identifier (atomic, vip, etc.).
|
||||
*/
|
||||
public static function log_event( $event_type, $key, $details = '', $environment = 'unknown' ) {
|
||||
// Only process 'error' and 'empty' events for provider error reporting
|
||||
if ( 'error' !== $event_type && 'empty' !== $event_type ) {
|
||||
// For non-reportable events, just do debug logging with rate limiting
|
||||
if ( self::should_log_event( $key, $event_type ) && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||
error_log( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
|
||||
sprintf(
|
||||
'Jetpack External Storage %s: %s in %s%s',
|
||||
$event_type,
|
||||
$key,
|
||||
$environment,
|
||||
$details ? ' - ' . $details : ''
|
||||
)
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// For 'empty' events, check delay mechanism first to avoid false positives
|
||||
// during sync between external storage and the database.
|
||||
// This is checked BEFORE rate limiting so we don't block legitimate reports.
|
||||
if ( 'empty' === $event_type && ! self::should_report_empty_state( $key ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply rate limiting only for events that will trigger provider notification
|
||||
if ( ! self::should_log_event( $key, $event_type ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Local debug logging (only when WP_DEBUG is enabled)
|
||||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||
error_log( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
|
||||
sprintf(
|
||||
'Jetpack External Storage %s: %s in %s%s',
|
||||
$event_type,
|
||||
$key,
|
||||
$environment,
|
||||
$details ? ' - ' . $details : ''
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Delegate to provider if it implements error handling
|
||||
if ( null !== self::$provider && method_exists( self::$provider, 'handle_error_event' ) ) {
|
||||
// @phan-suppress-next-line PhanUndeclaredMethod -- Optional method, checked via method_exists()
|
||||
self::$provider->handle_error_event( $event_type, $key, $details, $environment );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we should report an empty state based on delay mechanism.
|
||||
*
|
||||
* This prevents false positives during storage sync delays. On first encounter
|
||||
* of empty state, sets a transient. On subsequent encounters after the delay
|
||||
* threshold, allows reporting (indicating likely disconnection, not sync delay).
|
||||
*
|
||||
* Providers can customize the delay threshold by implementing get_empty_state_delay_threshold().
|
||||
*
|
||||
* @since 6.18.0
|
||||
*
|
||||
* @param string $key The key that was empty.
|
||||
* @return bool True if we should report this empty state, false otherwise.
|
||||
*/
|
||||
private static function should_report_empty_state( $key ) {
|
||||
$delay_key = 'jetpack_external_storage_empty_delay_' . $key;
|
||||
$first_empty_time = get_transient( $delay_key );
|
||||
|
||||
if ( false === $first_empty_time ) {
|
||||
// First time encountering empty state - set delay transient and don't report yet
|
||||
set_transient( $delay_key, time(), self::EMPTY_STATE_TRANSIENT_EXPIRY );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Default delay threshold (5 minutes)
|
||||
$delay_threshold = 5 * MINUTE_IN_SECONDS;
|
||||
|
||||
// Allow provider to customize delay threshold
|
||||
// A threshold of 0 is valid for providers where external storage is written first
|
||||
if ( null !== self::$provider && method_exists( self::$provider, 'get_empty_state_delay_threshold' ) ) {
|
||||
// @phan-suppress-next-line PhanUndeclaredMethod -- Optional method, checked via method_exists()
|
||||
$custom_threshold = self::$provider->get_empty_state_delay_threshold();
|
||||
if ( is_int( $custom_threshold ) && $custom_threshold >= 0 && $custom_threshold <= self::EMPTY_STATE_TRANSIENT_EXPIRY ) {
|
||||
$delay_threshold = $custom_threshold;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( time() - $first_empty_time ) >= $delay_threshold ) {
|
||||
// Delay threshold passed - likely disconnection, report it
|
||||
delete_transient( $delay_key );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an event should be logged based on rate limiting rules.
|
||||
*
|
||||
* This prevents log spam from noisy events by applying a simple one-hour
|
||||
* rate limit per key and event type combination. Also uses a static cache
|
||||
* to prevent duplicate logs within the same request.
|
||||
*
|
||||
* @since 6.18.0
|
||||
*
|
||||
* @param string $key The key that triggered the event.
|
||||
* @param string $event_type The event type (error, empty, unavailable).
|
||||
* @return bool True if the event should be logged, false if rate limited.
|
||||
*/
|
||||
private static function should_log_event( $key, $event_type = '' ) {
|
||||
// Combine event type and key for unique tracking
|
||||
$event_cache_key = $event_type . '_' . $key;
|
||||
|
||||
// Check static cache first (prevents multiple logs in same request)
|
||||
if ( isset( self::$logged_events[ $event_cache_key ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rate_limit_key = 'jetpack_ext_storage_rate_limit_' . $event_cache_key;
|
||||
|
||||
// Check if we're still within the rate limit period
|
||||
if ( get_transient( $rate_limit_key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark as logged in both caches
|
||||
self::$logged_events[ $event_cache_key ] = true;
|
||||
set_transient( $rate_limit_key, true, HOUR_IN_SECONDS );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -33,7 +33,7 @@ class Initial_State {
|
||||
'connectedPlugins' => REST_Connector::get_connection_plugins( false ),
|
||||
'wpVersion' => $wp_version,
|
||||
'siteSuffix' => $status->get_site_suffix(),
|
||||
'connectionErrors' => Error_Handler::get_instance()->get_verified_errors(),
|
||||
'connectionErrors' => Error_Handler::get_instance()->get_displayable_errors(),
|
||||
'isOfflineMode' => $status->is_offline_mode(),
|
||||
'calypsoEnv' => ( new Status\Host() )->get_calypso_env(),
|
||||
);
|
||||
@ -57,7 +57,7 @@ class Initial_State {
|
||||
* @return string
|
||||
*/
|
||||
public static function render() {
|
||||
return 'var JP_CONNECTION_INITIAL_STATE; typeof JP_CONNECTION_INITIAL_STATE === "object" || (JP_CONNECTION_INITIAL_STATE = JSON.parse(decodeURIComponent("' . rawurlencode( wp_json_encode( self::get_data() ) ) . '")));';
|
||||
return 'var JP_CONNECTION_INITIAL_STATE; typeof JP_CONNECTION_INITIAL_STATE === "object" || (JP_CONNECTION_INITIAL_STATE = ' . wp_json_encode( self::get_data(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ');';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user