fix(audit L6, L5): DesignLock atomar (INSERT IGNORE, Token, Übernahme per UPDATE, Release nur mit eigenem Token); Farben und Theme-Optionen teilen eine Sperre

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 23:52:38 +02:00
co-authored by Claude Sonnet 5.5
parent 522fc8ff4d
commit b59a0c045f
14 changed files with 206 additions and 88 deletions
+61
View File
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Support;
/**
* In-memory options table as $GLOBALS['wpdb'] that understands the three statements of DesignLock (INSERT IGNORE,
* conditional UPDATE, DELETE by token). $beforeInsert runs before a lock is inserted (a parallel request).
*/
final class LockTable extends \wpdb
{
/** @var array<string, string> option_name => option_value */
public array $rows = [];
public ?\Closure $beforeInsert = null;
public static function install(): self
{
return $GLOBALS['wpdb'] = new self();
}
public function query($sql)
{
if (preg_match("/^INSERT IGNORE .* VALUES \('([^']*)', '([^']*)', 'no'\)$/", $sql, $m) === 1) {
if ($this->beforeInsert !== null) {
($this->beforeInsert)();
}
if (isset($this->rows[$m[1]])) {
return 0;
}
$this->rows[$m[1]] = $m[2];
return 1;
}
$update = "/^UPDATE .* SET option_value = '([^']*)' WHERE option_name = '([^']*)' AND option_value = '([^']*)'$/";
if (preg_match($update, $sql, $m) === 1) {
if (($this->rows[$m[2]] ?? null) !== $m[3]) {
return 0;
}
$this->rows[$m[2]] = $m[1];
return 1;
}
$delete = "/^DELETE FROM .* WHERE option_name = '([^']*)' AND option_value = '([^']*)'$/";
if (preg_match($delete, $sql, $m) === 1 && ($this->rows[$m[1]] ?? null) === $m[2]) {
unset($this->rows[$m[1]]);
return 1;
}
return 0;
}
public function get_var($sql = null, $x = 0, $y = 0)
{
preg_match("/option_name = '([^']*)'/", (string) $sql, $m);
return $this->rows[$m[1]] ?? null;
}
}