Plugin Directory

Changeset 3472118


Ignore:
Timestamp:
03/01/2026 03:03:40 PM (5 weeks ago)
Author:
coinsnap
Message:
  1. 1.1.0
Location:
coinsnap-bitcoin-invoice-form
Files:
52 added
9 edited

Legend:

Unmodified
Added
Removed
  • coinsnap-bitcoin-invoice-form/trunk/assets/js/admin.js

    r3459088 r3472118  
    5252       
    5353       
    54         $('#coinsnapbif_btcpay_wizard_button').click(function(e) {
     54    $('#coinsnapbif_btcpay_wizard_button').click(function(e) {
    5555        e.preventDefault();
    56         const host = $('#btcpay_url').val();
     56        const host = $('#coinsnapbif_btcpay_url').val();
    5757    if (isCoinsnapBIFValidUrl(host)) {
    5858            let data = {
  • coinsnap-bitcoin-invoice-form/trunk/coinsnap-bitcoin-invoice-form.php

    r3459146 r3472118  
    44 * Plugin URI:         https://coinsnap.io/modules/bitcoin-invoice/
    55 * Description:        Generate and embed customizable Bitcoin Invoice Forms on your website. Customers can complete and pay invoices directly on your site with payment processing via Coinsnap or BTCPay Server.
    6  * Version:            1.0.3.2
     6 * Version:            1.1.0
    77 * Author:             Coinsnap
    88 * Author URI:         https://coinsnap.io/
     
    2525
    2626if(!defined('COINSNAPBIF_REFERRAL_CODE' ) ) { define( 'COINSNAPBIF_REFERRAL_CODE', 'D85536' );}
    27 if(!defined('COINSNAPBIF_VERSION' ) ) { define( 'COINSNAPBIF_VERSION', '1.0.3.2' );}
     27if(!defined('COINSNAPBIF_VERSION' ) ) { define( 'COINSNAPBIF_VERSION', '1.1.0' );}
    2828if(!defined('COINSNAPBIF_PHP_VERSION' ) ) { define( 'COINSNAPBIF_PHP_VERSION', '7.4' );}
    2929if(!defined('COINSNAP_CURRENCIES')){define( 'COINSNAP_CURRENCIES', array("EUR","USD","SATS","BTC","CAD","JPY","GBP","CHF","RUB") );}
  • coinsnap-bitcoin-invoice-form/trunk/readme.txt

    r3459146 r3472118  
    44Tags: Lightning, bitcoin, invoice form, BTCPay
    55Tested up to: 6.9
    6 Stable tag: 1.0.3.2
     6Stable tag: 1.1.0
    77License: GPL2
    88License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    250250= 1.0.3.2 :: 2026-02-11 =
    251251* Updated Coinsnap and BTCPay server errors handler
     252
     253= 1.1.0 :: 2026-03-01 =
     254* Update: added BTCPay server connection wizard on Settings page
     255* Update: deleted setting Disable Webhook Verification
  • coinsnap-bitcoin-invoice-form/trunk/src/Admin/class-coinsnapbif-admin-settings.php

    r3458758 r3472118  
    145145            function () {
    146146                $s = self::get_settings();
    147                 echo '<input type="url" class="regular-text" name="' . esc_attr( self::OPTION_KEY ) . '[btcpay_host]" value="' . esc_attr( $s['btcpay_host'] ) . '" />';
     147                echo '<input type="url" id="coinsnapbif_btcpay_url" class="regular-text" name="' . esc_attr( self::OPTION_KEY ) . '[btcpay_host]" value="' . esc_attr( $s['btcpay_host'] ) . '" /><br/><button class="button btcpay-apikey-link" type="button" id="coinsnapbif_btcpay_wizard_button" target="_blank">'. esc_html__('Generate API key','coinsnap-bitcoin-invoice-form') .'</button>';
    148148            },
    149149            'coinsnapbif-settings',
     
    202202            'coinsnapbif-settings',
    203203            'coinsnapbif_advanced'
    204         );
     204        );/*
    205205        add_settings_field(
    206206            'disable_webhook_verification',
     
    212212            'coinsnapbif-settings',
    213213            'coinsnapbif_advanced'
    214         );
     214        );*/
    215215    }
    216216
  • coinsnap-bitcoin-invoice-form/trunk/src/Providers/Payment/class-btcpayprovider.php

    r3459146 r3472118  
    6565            return array('error' => true,'message'=>__('BTCPay server request error','coinsnap-bitcoin-invoice-form'),'code' => $code, 'result' => $result);
    6666        }
    67     }
    68    
     67    }   
    6968   
    7069    /**
  • coinsnap-bitcoin-invoice-form/trunk/src/class-coinsnapbif-constants.php

    r3458758 r3472118  
    3333
    3434    /** BTCPay endpoint (relative to host). */
    35     public const BTCPAY_STORE_ENDPOINT = '/api/v1/stores/%s';
     35    public const BTCPAY_STORES_ENDPOINT = '/api/v1/stores';
     36        public const BTCPAY_STORE_ENDPOINT = '/api/v1/stores/%s';
    3637        public const BTCPAY_INVOICES_ENDPOINT = '/api/v1/stores/%s/invoices';
    3738        public const BTCPAY_WEBHOOKS_ENDPOINT = '/api/v1/stores/%s/webhooks';
  • coinsnap-bitcoin-invoice-form/trunk/src/class-coinsnapbif-plugin.php

    r3460775 r3472118  
    169169       
    170170    public function btcpayApiUrlHandler(){
    171            
     171            $_nonce = filter_input(INPUT_POST,'apiNonce',FILTER_SANITIZE_STRING);
     172            if ( !wp_verify_nonce( $_nonce, 'coinsnap-ajax-nonce' ) ) {
     173                wp_die('Unauthorized!', '', ['response' => 401]);
     174            }
     175
     176            if ( current_user_can( 'manage_options' ) ) {
     177                $host = filter_var(filter_input(INPUT_POST,'host',FILTER_SANITIZE_STRING), FILTER_VALIDATE_URL);
     178
     179                if ($host === false || (substr( $host, 0, 7 ) !== "http://" && substr( $host, 0, 8 ) !== "https://")) {
     180                    wp_send_json_error("Error validating BTCPayServer URL.");
     181                }
     182
     183                $permissions = array_merge([
     184                    'btcpay.store.canviewinvoices',
     185                    'btcpay.store.cancreateinvoice',
     186                    'btcpay.store.canviewstoresettings',
     187                    'btcpay.store.canmodifyinvoices'
     188                ],
     189                [
     190                    'btcpay.store.cancreatenonapprovedpullpayments',
     191                    'btcpay.store.webhooks.canmodifywebhooks',
     192                ]);
     193
     194                try {
     195                    // Create the redirect url to BTCPay instance.
     196                    $url = $this->getAuthorizeUrl(
     197                        $host,
     198                        $permissions,
     199                        'CoinsnapBIF',
     200                        true,
     201                        true,
     202                        home_url('?coinsnapBIF-settings-callback'),
     203                        null
     204                    );
     205
     206                    // Store the host to options before we leave the site.
     207                    coinsnap_settings_update(AdminSettings::OPTION_KEY,['btcpay_host' => $host]);
     208
     209                    // Return the redirect url.
     210                    wp_send_json_success(['url' => $url]);
     211                }
     212
     213                catch (\Throwable $e) {
     214
     215                }
     216            }
     217            wp_send_json_error("Error processing Ajax request.");
     218    }
     219   
     220    public function getAuthorizeUrl(string $baseUrl, array $permissions, ?string $applicationName, ?bool $strict, ?bool $selectiveStores, ?string $redirectToUrlAfterCreation, ?string $applicationIdentifier): string {
     221        $url = rtrim($baseUrl, '/') . '/api-keys/authorize';
     222
     223        $params = [];
     224        $params['permissions'] = $permissions;
     225        $params['applicationName'] = $applicationName;
     226        $params['strict'] = $strict;
     227        $params['selectiveStores'] = $selectiveStores;
     228        $params['redirect'] = $redirectToUrlAfterCreation;
     229        $params['applicationIdentifier'] = $applicationIdentifier;
     230
     231        // Take out NULL values
     232        $params = array_filter($params, function ($value) {
     233            return $value !== null;
     234        });
     235
     236        $queryParams = [];
     237
     238        foreach ($params as $param => $value) {
     239            if ($value === true) {
     240                $value = 'true';
     241            }
     242            if ($value === false) {
     243                $value = 'false';
     244            }
     245
     246            if (is_array($value)) {
     247                foreach ($value as $item) {
     248                    if ($item === true) {
     249                        $item = 'true';
     250                    }
     251                    if ($item === false) {
     252                        $item = 'false';
     253                    }
     254                    $queryParams[] = $param . '=' . urlencode((string)$item);
     255                }
     256            } else {
     257                $queryParams[] = $param . '=' . urlencode((string)$value);
     258            }
     259        }
     260
     261        $url .= '?' . implode("&", $queryParams);
     262        return $url;
    172263    }
    173264       
     
    503594    }
    504595}
     596
     597add_action('init', function() {
     598    // Setting up and handling custom endpoint for api key redirect from BTCPay Server.
     599    add_rewrite_endpoint('coinsnapBIF-settings-callback', EP_ROOT);
     600});
     601
     602// To be able to use the endpoint without appended url segments we need to do this.
     603add_filter('request', function($vars){
     604    if (isset($vars['coinsnapBIF-settings-callback'])) {
     605        $vars['coinsnapBIF-settings-callback'] = true;
     606        $vars['coinsnapBIF-nonce'] = wp_create_nonce('coinsnap-bitcoin-invoice-form-btcpay-nonce');
     607    }
     608    return $vars;
     609});
     610
     611if(!function_exists('coinsnap_settings_update')){
     612    function coinsnap_settings_update($option,$data){
     613       
     614        $form_data = get_option($option, []);
     615       
     616        foreach($data as $key => $value){
     617            $form_data[$key] = $value;
     618        }
     619       
     620        update_option($option,$form_data);
     621    }
     622}
     623
     624// Adding template redirect handling for coinsnapBIF-settings-callback.
     625add_action( 'template_redirect', function(){
     626   
     627    global $wp_query;
     628           
     629    // Only continue on a coinsnapBIF-settings-callback request.   
     630    if (!isset( $wp_query->query_vars['coinsnapBIF-settings-callback'])) {
     631        return;
     632    }
     633   
     634    if(!isset($wp_query->query_vars['coinsnapBIF-nonce']) || !wp_verify_nonce($wp_query->query_vars['coinsnapBIF-nonce'],'coinsnap-bitcoin-invoice-form-btcpay-nonce')){
     635        return;
     636    }
     637
     638    $CoinsnapBTCPaySettingsUrl = admin_url('/admin.php?page=coinsnapbif-settings');
     639   
     640    $rawData = file_get_contents('php://input');
     641    $form_data = get_option(AdminSettings::OPTION_KEY, []);
     642
     643    $btcpay_server_url = $form_data['btcpay_host'];
     644    $btcpay_api_key  = filter_input(INPUT_POST,'apiKey',FILTER_SANITIZE_FULL_SPECIAL_CHARS);
     645
     646    $request_url = $btcpay_server_url.'/api/v1/stores';
     647    $args = array(
     648                'method'  => 'GET',
     649                'headers' => array(
     650                    'Authorization' => 'token ' . $btcpay_api_key,
     651                    'Content-Type'  => 'application/json',
     652                ),
     653                'timeout' => 20
     654    );
     655
     656    $res = wp_remote_request( $request_url, $args );
     657    $code = wp_remote_retrieve_response_code( $res );
     658    $getstores = json_decode( wp_remote_retrieve_body( $res ), true );
     659           
     660            if($code >= 200 && $code < 300 && is_array($getstores)){
     661                if (count($getstores) < 1) {
     662                    //$messageAbort = __('Error on verifiying redirected API Key with stored BTCPay Server url. Aborting API wizard. Please try again or continue with manual setup.', 'coinsnap-bitcoin-invoice-form');
     663                    wp_redirect($CoinsnapBTCPaySettingsUrl);
     664                }
     665            }
     666                       
     667            // Data does get submitted with url-encoded payload, so parse $_POST here.
     668            if (!empty($_POST)) {
     669                $data['apiKey'] = filter_input(INPUT_POST,'apiKey',FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? null;
     670                if(isset($_POST['permissions'])){
     671                    $permissions = array_map('sanitize_text_field', wp_unslash($_POST['permissions']));
     672                    if(is_array($permissions)){
     673                        foreach ($permissions as $key => $value) {
     674                            $data['permissions'][$key] = sanitize_text_field($permissions[$key] ?? null);
     675                        }
     676                    }
     677                }
     678            }
     679   
     680            if (isset($data['apiKey']) && isset($data['permissions'])) {
     681
     682                $REQUIRED_PERMISSIONS = [
     683                    'btcpay.store.canviewinvoices',
     684                    'btcpay.store.cancreateinvoice',
     685                    'btcpay.store.canviewstoresettings',
     686                    'btcpay.store.canmodifyinvoices'
     687                ];
     688                $OPTIONAL_PERMISSIONS = [
     689                    'btcpay.store.cancreatenonapprovedpullpayments',
     690                    'btcpay.store.webhooks.canmodifywebhooks',
     691                ];
     692               
     693                $btcpay_server_permissions = $data['permissions'];
     694               
     695                $permissions = array_reduce($btcpay_server_permissions, static function (array $carry, string $permission) {
     696            return array_merge($carry, [explode(':', $permission)[0]]);
     697        }, []);
     698
     699        // Remove optional permissions so that only required ones are left.
     700        $permissions = array_diff($permissions, $OPTIONAL_PERMISSIONS);
     701
     702        $hasRequiredPermissions = (empty(array_merge(array_diff($REQUIRED_PERMISSIONS, $permissions), array_diff($permissions, $REQUIRED_PERMISSIONS))))? true : false;
     703               
     704                $hasSingleStore = true;
     705                $storeId = null;
     706        foreach ($btcpay_server_permissions as $perms) {
     707                    if (2 !== count($exploded = explode(':', $perms))) { return false; }
     708                    if (null === ($receivedStoreId = $exploded[1])) { $hasSingleStore = false; }
     709                    if ($storeId === $receivedStoreId) { continue; }
     710                    if (null === $storeId) { $storeId = $receivedStoreId; continue; }
     711                    $hasSingleStore = false;
     712        }
     713               
     714                if ($hasSingleStore && $hasRequiredPermissions) {
     715
     716                    coinsnap_settings_update(
     717                        AdminSettings::OPTION_KEY,[
     718                        'btcpay_api_key' => $data['apiKey'],
     719                        'btcpay_store_id' => explode(':', $btcpay_server_permissions[0])[1],
     720                        'payment_provider' => 'btcpay'
     721                        ]);
     722                   
     723                    wp_redirect($CoinsnapBTCPaySettingsUrl);
     724                    exit();
     725                }
     726                else {
     727                    wp_redirect($CoinsnapBTCPaySettingsUrl);
     728                    exit();
     729                }
     730            }
     731
     732    wp_redirect($CoinsnapBTCPaySettingsUrl);
     733    exit();
     734});
Note: See TracChangeset for help on using the changeset viewer.