Post with API Key - Error Invalid Token

Status
Not open for further replies.

technologic

New Member
Jan 25, 2020
3
0
1
41
I'm trying to utilize a user's API key to allow me to post an update to an extension name programmatically. Including said key in URL, for example:

https://domain.com/app/extensions/e...d=f4a3809c-fa0c-47e6-967a-442113544ba1&page=0

This seems to satisfy the auth requirement when I post the form variables, as I get in response the list of extensions from extensions.php instead of the login page. However, the problem is that the response also includes the error message "Invalid Token" unless I first perform a GET and extract from the response the hidden token at the bottom of the form.

My intent here is not to have to perform a get and parse a response for a token where said token isn't even identified by a consistent ID - both the name and value are variable and there's no useful naming of the HTML element, so this makes for a really sloppy programmatic solution. The key value pair that has to be extracted and included in the post to succeed looks like
<input type='hidden' name='8cc63d24069b30110abd2325ba2248d8b9bed1f7c71e691c080ec34759cae0e5' value='e5b1e6a89d636cd3e81be34217b296d139055c8d936f9f8dd846786719dde889'>

Does anybody know of a way to post an update using just the API key + form data without having to parse this not-so-well-formed key value pair provided by an immediately preceding get?
 

DigitalDaz

Administrator
Staff member
Sep 29, 2016
3,038
556
113
I think the deal here is that there are no RESTful endpoints in the code. There is a separate commercial API that probably omits the CSRF token. You could always create your own endpoints for what you need.
 

technologic

New Member
Jan 25, 2020
3
0
1
41
I think the deal here is that there are no RESTful endpoints in the code. There is a separate commercial API that probably omits the CSRF token. You could always create your own endpoints for what you need.
Thanks, Daz. I appreciate your reply! A custom endpoint in this case isn't out of the question because the functionality we seek is pretty limited here, but I suppose I am a little stumped as far as where to start. Sure, FreeSwitch offers a variety of mechanisms to potentially effect such changes, such as Lua/Python/Perl/PHP ESLs, however, I'm of the impression I wouldn't really want to go that way because I'd presumably want to effect the changes in the Fusion DB directly, and then somehow have Fusion commit those changes to FreeSwitch, no? Bottom line, I assume it would be a bad idea to approach this as a strictly FreeSwitch type problem, which I guess brings me back to feeling like I'm missing something about the adequacy of Fusions's documentation for how to approach such a dev project in Fusion. Any useful developer resources that are Fusion specific you could potentially point me to by chance?
 

xisonc

New Member
May 22, 2017
5
2
3
35
I worked around it using CURL and having it save cookies and such, writing the code to look like a user is authenticating and POSTing the request.

I'm only using it to pull logs for certain situations but it works no issue.

I've written it in PHP and wrapped it in a function for easier use, here's a slightly modified version of it:

PHP:
<?php

    // store cookie files here
    define('PATH_VAR', '/www/path/to/wherever/');

    // here's the wrapper function
    function PBX_API_Request($action, $params=[], $method='POST')
    {
        // this is pulled in through a config system built into my framework
        // but we'll emulate it's sturcture here just to show how it works
        $config = [    'url'    =>    'https://mypbx.mydomain.net/',
                      'user'    =>    'myusername'
                      'pass'    =>    'mypassword'];
    
        $URL = $config['url'] . $action;

        // is this GET a request? Append vars to query string
        if( strtoupper($method) === 'GET' && sizeof($params) > 0 )
        {
            $URL.= '?'.http_build_query($params);
        }

        // make curl object
        $ch =    curl_init();
                curl_setopt($ch, CURLOPT_URL, $URL);
                curl_setopt($ch, CURLOPT_TIMEOUT, 300);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_HEADER, true);
                curl_setopt($ch, CURLOPT_COOKIESESSION, true );
                curl_setopt($ch, CURLOPT_COOKIEJAR, PATH_VAR . 'curl/cookies_' .md5($action). '.dat');
                curl_setopt($ch, CURLOPT_COOKIEFILE, PATH_VAR . 'curl/cookies_' .md5($action). '.dat');

        // is this a POST request? Pass the params
        if( strtoupper($method) === 'POST' )
        {
            // we overrite username and password from our config defined above
            $params['username'] = $config['user'];
            $params['password'] = $config['pass'];

            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        }

        $result = curl_exec($ch);

        $errNo = curl_errno($ch);
        $errMsg = curl_error($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        $headerlen    = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $headers    = substr($result, 0, $headerlen);
        $body        = substr($result, $headerlen);

        curl_close($ch);

        if( $errNo )
        {
            $result = null;
            throw new \ErrorException('CURL Error ('.$errNo.'): '.$errMsg);
        }

        return ['status'=>$status, 'body'=>$body, 'headers'=>$headers];
    }

/*
 * example using the function above
 * this is how to use it to get what you want
 */
    // variables to pass
    $vars = [
        'show'                =>    'all',
        'start_stamp_begin'    =>    date('Y-m-d H:i', ($start_time+$config['time_offset'])), // format to '2018-12-01 00:00'
        'start_stamp_end'    =>    date('Y-m-d H:i', ($end_time+$config['time_offset'])),
        'export_format'        =>    'csv',
        'order'                =>    'desc',
        'order_by'            =>    'start_epoch'
    ];

    $get_cdr = PBX_API_Request('app/xml_cdr/xml_cdr_export.php', $vars, 'POST');

    // check the http response status
    if( intval($fetch['status']) != 200 )
    {
        echo 'error status != 200, probably an error, grumble grumble';
        continue;
    }

    // ensure there is data to process
    if( strlen($fetch['body']) == 0 )
    {
        echo 'error no data';
        continue;
    }

    // get the data you want by parsing $get_cdr['body']
    var_dump($get_cdr['body']);

I honestly don't know if this will work with other things or not, but my very limited messing around it does what I need it to.
 
Status
Not open for further replies.