Files
unsupervised-scheduler/templates/admin/access.php
T
KydoimosandClaude Opus 5 1847159e31 Fix five findings from a security assessment of the plugin
The assessment looked for three things: whether students can reach each
other's bookings, whether payment settings can be dodged, and whether the
plugin opens a way into the rest of the install. The student-isolation and
payment paths held up. These are what did not.

- The front-end login form told WordPress not to work out whether the site
  was secure, so on HTTPS every student's session cookie was issued without
  the Secure flag. wp_signon() only derives it from is_ssl() when the second
  argument is left at its default; an explicit false reads like "no
  preference" and is not.

- The update check took whatever download URL the release API returned and
  handed it to core, which unpacks it over the installed plugin. The package
  must now be https on git.unsupervised.ca exactly, compared on the parsed
  host so a lookalike name cannot pass.

- Uninstalling dropped 2 of 14 tables and left the Stripe secret and webhook
  signing key in wp_options. Removal is now a choice made in advance on
  Access -> Plugin removal: records are kept unless the owner opts in (with a
  typed confirmation), while credentials and the borrowed core registration
  settings go every time.

- Open registration switches on the site-wide users_can_register and makes
  Student the default role, arming any other signup form on the site to mint
  students who could book and be billed immediately. The pending state is now
  decided once, on user_register, rather than by whichever form created the
  account.

- Cancel and withdraw answered "not yours" differently from "does not exist",
  which let a signed-in student enumerate the studio's bookings. Both now
  give the same 404.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 11:55:53 -03:00

103 lines
6.1 KiB
PHP

<?php
declare(strict_types=1);
if (! defined('ABSPATH')) {
exit;
}
/**
* @var bool $adminsAreStudioAdmins
* @var bool $adminsAreInstructors
* @var bool $deleteDataOnUninstall
* @var string $error Why the data-removal choice was refused, if it was.
*/
?>
<div class="wrap">
<h1><?php esc_html_e('Access', 'unsupervised-schedular'); ?></h1>
<div class="notice notice-info inline">
<p>
<?php esc_html_e('Control whether WordPress administrators automatically gain studio-admin and instructor abilities. Both are on by default, so the site owner can run the studio and teach from one account. Turn them off when dedicated Studio Admin or Instructor accounts run the studio instead.', 'unsupervised-schedular'); ?>
</p>
</div>
<?php if ($error !== '') : ?>
<div class="notice notice-error inline">
<p><?php echo esc_html($error); ?></p>
</div>
<?php endif; ?>
<form method="post">
<?php wp_nonce_field('usc_access_action'); ?>
<input type="hidden" name="usc_action" value="save">
<table class="form-table">
<tr>
<th scope="row"><?php esc_html_e('WordPress administrators', 'unsupervised-schedular'); ?></th>
<td>
<fieldset>
<label>
<input type="checkbox" name="grant_studio" value="1" <?php checked($adminsAreStudioAdmins); ?>>
<?php esc_html_e('Are Studio Admins', 'unsupervised-schedular'); ?>
</label>
<p class="description"><?php esc_html_e('Manage offerings, questions, policies, students, invites, billing, and reports.', 'unsupervised-schedular'); ?></p>
<br>
<label>
<input type="checkbox" name="grant_instructor" value="1" <?php checked($adminsAreInstructors); ?>>
<?php esc_html_e('Are Instructors', 'unsupervised-schedular'); ?>
</label>
<p class="description"><?php esc_html_e('Manage their own availability and see their own lessons — needed to set availability and be booked from the administrator account.', 'unsupervised-schedular'); ?></p>
</fieldset>
<p class="description">
<?php esc_html_e('You are a WordPress administrator, so this page stays available even if you turn both options off.', 'unsupervised-schedular'); ?>
</p>
</td>
</tr>
</table>
<h2><?php esc_html_e('Plugin removal', 'unsupervised-schedular'); ?></h2>
<p class="description" style="max-width:46em;">
<?php esc_html_e('Deleting a plugin happens on the Plugins screen, and WordPress gives it nothing to ask you at the time — so the answer is given here, in advance.', 'unsupervised-schedular'); ?>
</p>
<table class="form-table">
<tr>
<th scope="row"><?php esc_html_e('Always removed', 'unsupervised-schedular'); ?></th>
<td>
<p class="description">
<?php esc_html_e('Your Stripe secret key and webhook signing secret are forgotten whenever this plugin is deleted, whatever you choose below. They can be pasted back in from the Stripe dashboard in a minute; leaving live keys on a site that no longer has the code to use them cannot be undone as easily. The two WordPress settings open registration borrows — whether anyone can register, and the role new users get — are put back as they were, too.', 'unsupervised-schedular'); ?>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('Studio records', 'unsupervised-schedular'); ?></th>
<td>
<fieldset>
<label>
<input type="checkbox" name="delete_data" value="1" <?php checked($deleteDataOnUninstall); ?>>
<?php esc_html_e('Erase everything when the plugin is deleted', 'unsupervised-schedular'); ?>
</label>
<p class="description">
<?php esc_html_e('Off by default: deleting the plugin leaves your lessons, enrolments, payments, credits, intake answers, policy agreements, invites and family links in the database, so reinstalling picks up exactly where you left off — and a deletion during a migration or a bit of troubleshooting costs you nothing.', 'unsupervised-schedular'); ?>
</p>
<p class="description">
<strong><?php esc_html_e('Turn it on and there is no way back.', 'unsupervised-schedular'); ?></strong>
<?php esc_html_e('Every table this plugin made is dropped, every setting and student record it stored is deleted, and the Studio Admin, Instructor and Student roles are removed. WordPress does not ask twice and there is no undo. Take a database backup first if the studio has ever taken a payment.', 'unsupervised-schedular'); ?>
</p>
<?php if (! $deleteDataOnUninstall) : ?>
<p>
<label for="usc-delete-confirm"><?php esc_html_e('To turn it on, type DELETE:', 'unsupervised-schedular'); ?></label>
<input type="text" name="delete_data_confirm" id="usc-delete-confirm" value="" autocomplete="off" class="regular-text" style="max-width:12em;">
</p>
<?php else : ?>
<p class="description">
<?php esc_html_e('Currently on. Untick the box and save to turn it off again.', 'unsupervised-schedular'); ?>
</p>
<?php endif; ?>
</fieldset>
</td>
</tr>
</table>
<?php submit_button(esc_html__('Save Access Settings', 'unsupervised-schedular')); ?>
</form>
</div>