<?php /** * Class for intializing and displaying all admin settings * * @package LBRYPress */ class LBRY_Admin { private $options; /** * LBRY_Admin Constructor */ public function __construct() { add_action('admin_menu', array($this, 'create_menu_pages')); add_action('admin_init', array($this, 'page_init')); add_action('admin_init', array($this, 'wallet_balance_warning')); add_action('admin_post_lbry_add_channel', array($this, 'add_channel')); } /** * Creates the options page in the WP admin interface */ public function create_menu_pages() { add_menu_page( __('LBRYPress Settings', 'lbrypress'), __('LBRYPress', 'lbrypress'), 'manage_options', LBRY_ADMIN_PAGE, '', plugin_dir_url(LBRY_PLUGIN_FILE) . '/admin/images/lbry-logo.svg' ); add_submenu_page( LBRY_ADMIN_PAGE, __('LBRYPress Settings', 'lbrypress'), __('Settings', 'lbrypress'), 'manage_options', LBRY_ADMIN_PAGE, array($this, 'options_page_html') ); add_submenu_page( LBRY_ADMIN_PAGE, __('LBRYPress Help', 'lbrypress'), __('Help', 'lbrypress'), 'manage_options', 'lbrypress-help', array($this, 'help_page_html') ); } /** * Registers all settings for the plugin */ public function page_init() { // Register the LBRY Setting array register_setting(LBRY_SETTINGS_GROUP, LBRY_SETTINGS, array('sanitize_callback' => array($this, 'sanitize'))); // Add Required Settings Sections add_settings_section( LBRY_SETTINGS_SECTION_GENERAL, // ID 'General Settings', // Title array( $this, 'general_section_info' ), // Callback LBRY_ADMIN_PAGE // Page ); // Add all settings fields add_settings_field( LBRY_WALLET, 'LBRY Wallet Address', array( $this, 'wallet_callback' ), LBRY_ADMIN_PAGE, LBRY_SETTINGS_SECTION_GENERAL ); add_settings_field( LBRY_SPEECH, 'Spee.ch URL', array( $this, 'speech_callback' ), LBRY_ADMIN_PAGE, LBRY_SETTINGS_SECTION_GENERAL ); add_settings_field( LBRY_SPEECH_CHANNEL, 'Spee.ch Channel', array( $this, 'speech_channel_callback' ), LBRY_ADMIN_PAGE, LBRY_SETTINGS_SECTION_GENERAL ); add_settings_field( LBRY_SPEECH_PW, 'Spee.ch Password', array( $this, 'speech_pw_callback' ), LBRY_ADMIN_PAGE, LBRY_SETTINGS_SECTION_GENERAL ); add_settings_field( LBRY_LICENSE, 'LBRY Publishing License', array( $this, 'license_callback' ), LBRY_ADMIN_PAGE, LBRY_SETTINGS_SECTION_GENERAL ); add_settings_field( LBRY_LBC_PUBLISH, 'LBC Per Publish', array( $this, 'lbc_publish_callback' ), LBRY_ADMIN_PAGE, LBRY_SETTINGS_SECTION_GENERAL ); } /** * Returns the Options Page HTML for the plugin */ public function options_page_html() { // Set class property to be referenced in callbacks $this->options = get_option(LBRY_SETTINGS); require_once(LBRY_ABSPATH . 'templates/options_page.php'); } /** * Returns the Help Page HTML for the plugin */ public function help_page_html() { require_once(LBRY_ABSPATH . 'templates/help_page.php'); } /** * Sanitizes setting input * // COMBAK Potentially sanitize more */ public function sanitize($input) { if (!empty($input[LBRY_SPEECH_CHANNEL])) { $channel = $input[LBRY_SPEECH_CHANNEL]; $channel = str_replace('@', '', $channel); $input[LBRY_SPEECH_CHANNEL] = $channel; } if (!empty($input[LBRY_SPEECH_PW])) { $encrypted = $this->encrypt($input['lbry_speech_pw']); $input[LBRY_SPEECH_PW] = $encrypted; } else { // If we have a password and its empty, keep orginal password if (!empty(get_option(LBRY_SETTINGS)[LBRY_SPEECH_PW])) { $input[LBRY_SPEECH_PW] = get_option(LBRY_SETTINGS)[LBRY_SPEECH_PW]; } } return $input; } /** * Section info for the General Section */ public function general_section_info() { print 'This is where you can configure how LBRYPress will distribute your content:'; } /** * Prints Wallet input */ public function wallet_callback() { // Get first available account address from Daemon $address = LBRY()->daemon->address_list(); $address = is_array($address) && !empty($address) ? $address[0]->address : ''; printf( '<input type="text" id="%1$s" name="%2$s[%1$s]" value="%3$s" readonly />', LBRY_WALLET, LBRY_SETTINGS, $address ); } /** * Prints Spee.ch input */ public function speech_callback() { printf( '<input type="text" id="%1$s" name="%2$s[%1$s]" value="%3$s" placeholder="https://your-speech-address.com"/>', LBRY_SPEECH, LBRY_SETTINGS, isset($this->options[LBRY_SPEECH]) ? esc_attr($this->options[LBRY_SPEECH]) : '' ); } /** * Prints Spee.ch channel input */ public function speech_channel_callback() { printf( '<span>@</span><input type="text" id="%1$s" name="%2$s[%1$s]" value="%3$s" placeholder="your-channel"/>', LBRY_SPEECH_CHANNEL, LBRY_SETTINGS, isset($this->options[LBRY_SPEECH_CHANNEL]) ? esc_attr($this->options[LBRY_SPEECH_CHANNEL]) : '' ); } /** * Prints Spee.ch password input */ public function speech_pw_callback() { printf( '<input type="password" id="%1$s" name="%2$s[%1$s]" value="" placeholder="Leave empty for same password"', LBRY_SPEECH_PW, LBRY_SETTINGS ); } /** * Prints License input */ public function license_callback() { // TODO: Maybe make this more elegant? $options = ''; // Create options list, select current license // foreach (LBRY()->licenses as $value => $name) { $selected = $this->options[LBRY_LICENSE] === $value; $options .= '<option value="' . $value . '"'; if ($selected) { $options .= ' selected'; } $options .= '>'. $name . '</option>'; } printf( '<select id="%1$s" name="%2$s[%1$s]">%3$s</select>', LBRY_LICENSE, LBRY_SETTINGS, $options ); } /** * Prints LBC per publish input */ public function lbc_publish_callback() { printf( '<input type="number" id="%1$s" name="%2$s[%1$s]" value="%3$s" min="0.01" step="0.01"/>', LBRY_LBC_PUBLISH, LBRY_SETTINGS, $this->options[LBRY_LBC_PUBLISH] ); } /** * Handles new channel form submission */ public function add_channel() { $redirect_url = admin_url('options-general.php?page=' . LBRY_ADMIN_PAGE); // Check that nonce if (! isset($_POST['_lbrynonce']) || ! wp_verify_nonce($_POST['_lbrynonce'], 'lbry_add_channel')) { LBRY()->notice->set_notice('error'); } elseif (! isset($_POST['new_channel']) || ! isset($_POST['bid_amount'])) { LBRY()->notice->set_notice('error', 'Must supply both channel name and bid amount'); } else { $new_channel = $_POST['new_channel']; $bid_amount = $_POST['bid_amount']; // Try to add the new channel try { $result = LBRY()->daemon->channel_new($new_channel, $bid_amount); // Tell the user it takes some time to go through LBRY()->notice->set_notice('success', 'Successfully added a new channel! Please wait a few minutes for the bid to process.', true); } catch (\Exception $e) { LBRY()->notice->set_notice('error', $e->getMessage(), false); } } wp_safe_redirect($redirect_url); exit(); } /** * Checks at most once an hour to see if the wallet balance is too low */ // IDEA: Check user permissions possibly public static function wallet_balance_warning() { // See if we've checked in the past two hours if (!get_transient('lbry_wallet_check')) { $balance = LBRY()->daemon->wallet_balance(); if ($balance < get_option(LBRY_SETTINGS)[LBRY_LBC_PUBLISH] * 20) { // If LBRY Balance is low, send email, but only once per day if (!get_transient('lbry_wallet_warning_email')) { $email = get_option('admin_email'); $subject = 'Your LBRYPress Wallet Balance is Low!'; $message = "You LBRY Wallet for your wordpress installation at " . site_url() . " is running very low.\r\n\r\nYou currently have " . $balance . ' LBC left in your wallet. In order to keep publishing to the LBRY network, please add some LBC to your account.'; wp_mail($email, $subject, $message); set_transient('lbry_wallet_warning_email', true, DAY_IN_SECONDS); } } set_transient('lbry_wallet_check', true, 2 * HOUR_IN_SECONDS); } } private function encrypt($plaintext) { $ivlen = openssl_cipher_iv_length($cipher="AES-256-CTR"); $iv = openssl_random_pseudo_bytes($ivlen); $ciphertext_raw = openssl_encrypt($plaintext, $cipher, wp_salt(), $options=OPENSSL_RAW_DATA, $iv); $hmac = hash_hmac('sha256', $ciphertext_raw, wp_salt(), $as_binary=true); return base64_encode($iv.$hmac.$ciphertext_raw); } private function decrypt($ciphertext) { $c = base64_decode($ciphertext); $ivlen = openssl_cipher_iv_length($cipher="AES-256-CTR"); $iv = substr($c, 0, $ivlen); $hmac = substr($c, $ivlen, $sha2len=32); $ciphertext_raw = substr($c, $ivlen+$sha2len); $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, wp_salt(), $options=OPENSSL_RAW_DATA, $iv); $calcmac = hash_hmac('sha256', $ciphertext_raw, wp_salt(), $as_binary=true); if (hash_equals($hmac, $calcmac)) {//PHP 5.6+ timing attack safe comparison return $original_plaintext; } return false; } public function get_speech_pw() { $ciphertext = get_option(LBRY_SETTINGS)[LBRY_SPEECH_PW]; if (empty($ciphertext)) { return false; } return $this->decrypt($ciphertext); } }