] * : table, json, csv or yaml. * --- * default: table * --- * * ## EXAMPLES * * wp stoutwall list * * @subcommand list * * @param array $args Positional arguments. * @param array $assoc_args Named arguments. * @return void */ public function list_($args, $assoc_args) { $options = stoutwall_get_options(); $rows = []; foreach (array_keys(stoutwall_default_switches()) as $key) { $rows[] = ['protection' => $key, 'enabled' => empty($options[$key]) ? 'no' : 'yes']; } WP_CLI\Utils\format_items($this->format($assoc_args), $rows, ['protection', 'enabled']); } /** * Checks whether each protection that is on is really in effect. * * ## OPTIONS * * [--format=] * : table, json, csv or yaml. * --- * default: table * --- * * ## EXAMPLES * * wp stoutwall status * * @param array $args Positional arguments. * @param array $assoc_args Named arguments. * @return void */ public function status($args, $assoc_args) { $rows = []; $errors = 0; foreach (Stoutwall_Security::checkModulesStatus() as $key => $item) { $rows[] = ['protection' => $key, 'state' => $item['state'], 'message' => $item['message']]; $errors += 'error' === $item['state'] ? 1 : 0; } WP_CLI\Utils\format_items($this->format($assoc_args), $rows, ['protection', 'state', 'message']); if ($errors) { WP_CLI::halt(1); } } /** * Turns protections on. * * ## OPTIONS * * ... * : One or more protection keys (see `wp stoutwall list`), or "all". * * ## EXAMPLES * * wp stoutwall enable security_headers hsts * * @param array $args Positional arguments. * @return void */ public function enable($args) { $this->toggle($args, 1); } /** * Turns protections off. * * ## OPTIONS * * ... * : One or more protection keys (see `wp stoutwall list`), or "all". * * ## EXAMPLES * * wp stoutwall disable disable_xmlrpc * * @param array $args Positional arguments. * @return void */ public function disable($args) { $this->toggle($args, 0); } /** * Prints the settings as JSON, or saves them to a file. * * ## OPTIONS * * [] * : File to write. Prints to the screen when omitted. * * ## EXAMPLES * * wp stoutwall export > stoutwall.json * * @param array $args Positional arguments. * @return void */ public function export($args) { $json = Stoutwall_Admin::exportJson(); if (empty($args[0])) { WP_CLI::line($json); return; } if (false === file_put_contents($args[0], $json)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents WP_CLI::error(sprintf('Could not write %s.', $args[0])); } WP_CLI::success(sprintf('Settings saved to %s.', $args[0])); } /** * Imports settings from a JSON file created by export. * * ## OPTIONS * * * : JSON file, or "-" to read from standard input. * * ## EXAMPLES * * wp stoutwall import stoutwall.json * * @param array $args Positional arguments. * @return void */ public function import($args) { $json = '-' === $args[0] ? stream_get_contents(STDIN) : @file_get_contents($args[0]); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged,WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents if (false === $json) { WP_CLI::error(sprintf('Could not read %s.', $args[0])); } $import = Stoutwall_Admin::parseImport((string) $json); if (null === $import) { WP_CLI::error('This is not a Stoutwall settings file.'); } Stoutwall_Admin::applyImport($import); WP_CLI::success('Settings imported.'); } /** * Lists IP addresses that are locked out after too many failed logins. * * ## OPTIONS * * [--format=] * : table, json, csv or yaml. * --- * default: table * --- * * @param array $args Positional arguments. * @param array $assoc_args Named arguments. * @return void */ public function lockouts($args, $assoc_args) { $rows = []; foreach (Stoutwall_Login_Limiter::activeLockouts() as $hash => $entry) { $rows[] = [ 'id' => $hash, 'ip' => $entry['ip'], 'until' => wp_date('Y-m-d H:i:s', $entry['until']), 'lockout' => $entry['count'], ]; } if (!$rows) { WP_CLI::log('No IP is locked out.'); return; } WP_CLI\Utils\format_items($this->format($assoc_args), $rows, ['id', 'ip', 'until', 'lockout']); } /** * Removes login lockouts. * * ## OPTIONS * * [] * : IP address or lockout id (see `wp stoutwall lockouts`). * * [--all] * : Remove every lockout. * * ## EXAMPLES * * wp stoutwall unlock 203.0.113.7 * wp stoutwall unlock --all * * @param array $args Positional arguments. * @param array $assoc_args Named arguments. * @return void */ public function unlock($args, $assoc_args) { if (!empty($assoc_args['all'])) { WP_CLI::success(sprintf('%d lockout(s) removed.', Stoutwall_Login_Limiter::unlock())); return; } if (empty($args[0])) { WP_CLI::error('Pass an IP address or lockout id, or --all.'); } if (!Stoutwall_Login_Limiter::unlock($args[0])) { WP_CLI::error('No lockout found for that IP or id.'); } WP_CLI::success('Lockout removed.'); } /** * Manages IP addresses that are never locked out. * * ## OPTIONS * * [] * : list, add or remove. * --- * default: list * options: * - list * - add * - remove * --- * * [...] * : IP addresses or CIDR ranges. * * ## EXAMPLES * * wp stoutwall allowlist * wp stoutwall allowlist add 203.0.113.7 198.51.100.0/24 * wp stoutwall allowlist remove 203.0.113.7 * * @param array $args Positional arguments. * @return void */ public function allowlist($args) { $action = isset($args[0]) ? $args[0] : 'list'; $entries = array_slice($args, 1); $current = stoutwall_get_allowlist(); if ('list' === $action) { if (!$current) { WP_CLI::log('No allowed IP addresses.'); } foreach ($current as $entry) { WP_CLI::line($entry); } return; } if (!$entries) { WP_CLI::error('Pass one or more IP addresses or ranges.'); } if ('add' === $action) { $invalid = stoutwall_save_allowlist(array_merge($current, $entries)); } else { $remove = array_map('stoutwall_normalize_ip_entry', $entries); $invalid = stoutwall_save_allowlist(array_diff($current, $remove)); } if ($invalid) { WP_CLI::warning('Skipped invalid entries: ' . implode(', ', $invalid)); } WP_CLI::success(sprintf('%d allowed entr%s.', count(stoutwall_get_allowlist()), 1 === count(stoutwall_get_allowlist()) ? 'y' : 'ies')); } /** * Prints server rules that match the protections that are on. * * ## OPTIONS * * [] * : apache, litespeed, openlitespeed or nginx. Detected when omitted. * * ## EXAMPLES * * wp stoutwall rules nginx * * @param array $args Positional arguments. * @return void */ public function rules($args) { $server = !empty($args[0]) ? $args[0] : Stoutwall_Server_Rules::detect(); if (!isset(Stoutwall_Server_Rules::servers()[$server])) { WP_CLI::error('Pass a server: ' . implode(', ', array_keys(Stoutwall_Server_Rules::servers())) . '.'); } WP_CLI::line(Stoutwall_Server_Rules::generate($server)); } /** * Runs the security audit. * * ## OPTIONS * * [--live] * : Also run the tests that make requests to the site. * * [--format=] * : table, json, csv or yaml. * --- * default: table * --- * * @param array $args Positional arguments. * @param array $assoc_args Named arguments. * @return void */ public function audit($args, $assoc_args) { $items = Stoutwall_Audit::run(!empty($assoc_args['live'])); WP_CLI\Utils\format_items($this->format($assoc_args), $items, ['id', 'status', 'label', 'description']); foreach ($items as $item) { if ('critical' === $item['status']) { WP_CLI::halt(1); } } } /** * Liga ou desliga chaves. * * @param array $keys Chaves. * @param int $value 1 ou 0. * @return void */ private function toggle($keys, $value) { $switches = array_keys(stoutwall_default_switches()); $keys = in_array('all', $keys, true) ? $switches : $keys; $unknown = array_diff($keys, $switches); if ($unknown) { WP_CLI::error(sprintf('Unknown protection: %s. See `wp stoutwall list`.', implode(', ', $unknown))); } $options = stoutwall_get_options(); foreach ($keys as $key) { $options[$key] = $value; } update_option('stoutwall_options', stoutwall_sanitize_options($options)); WP_CLI::success(sprintf('%s: %s.', $value ? 'Enabled' : 'Disabled', implode(', ', $keys))); } /** * Formato de saĆ­da pedido. * * @param array $assoc_args Argumentos nomeados. * @return string */ private function format($assoc_args) { return isset($assoc_args['format']) ? $assoc_args['format'] : 'table'; } }