My openstack temporary URL keeps being invalid - php

I try to generate temporary URLs for my Openstack ObjectStorage in a PHP application.
I've followed their documentation but even their python example isn't working.
So far, here is my generator :
class TempUrlGenerator implements ITempUrlGenerator
{
//See https://docs.openstack.org/swift/latest/api/temporary_url_middleware.html for details.
public function generate(string $url, int $validity = 5): string
{
$timestamp = time() + ($validity * 60);
return sprintf(
'%s?temp_url_sig=%s&temp_url_expires=%s',
$url,
$this->generateSignature($url, $timestamp),
$timestamp
);
}
private function generateSignature(string $url, int $timestamp): string
{
$body = sprintf(
'%s\n%s\n%s',
'GET',
$timestamp,
$this->getPath($url)
);
return hash_hmac('sha1', $body, trim(getenv('OPENSTACK_TEMPURL_KEY')));
}
private function getPath(string $url): string
{
$exploded = explode('/v1/', $url);
return sprintf('/v1/%s', $exploded[1]);
}
}
URL is the whole, complete URL (https://myserver.host.com/v1/...), validity is the number of minutes I want to keep my URL valid.
Beside that, the env variable is my secret key. I've already checked using a HEAD call on my account and my containers that the key is, indeed, uploaded on them with the good header. (X-Account-Meta-Temp-URL-Key and X-Container-Meta-Temp-URL-Key).
I've also checked multiple examples and implementations.
Yet I keep getting 401 invalid temp url when I try them.
Do you have any clue why or how I can troubleshot that ? Maybe is there some kind of setting on our server to check ?
Regards,

Related

Bit-Wasp/bitcoin-php Generate Wallet from Extended Public Key

I have been working around Bit-Wasp/bitcoin-php library for a while now and I encountered problems with it that I cannot resolve.
I have this as my code:
public function bitcoinWalletFromPublicKey($key, $index) {
$adapter = Bitcoin::getEcAdapter();
if (config('market.btc_network') == "mainnet") {
$btc = NetworkFactory::bitcoin();
$bitcoinPrefixes = new BitcoinRegistry();
} else {
$btc = NetworkFactory::bitcoinTestnet();
$bitcoinPrefixes = new BitcoinTestnetRegistry();
}
$slip132 = new Slip132(new KeyToScriptHelper($adapter));
$pubkeytype=substr($key, 0, 4);
if ($pubkeytype=='xpub' || $pubkeytype =='tpub') $pubPrefix = $slip132->p2pkh($bitcoinPrefixes);
if ($pubkeytype=='ypub') $pubPrefix = $slip132->p2shP2wpkh($bitcoinPrefixes);
if ($pubkeytype=='zpub' || $pubkeytype =='vpub') $pubPrefix = $slip132->p2wpkh($bitcoinPrefixes);
$config = new GlobalPrefixConfig([
new NetworkConfig($btc, [$pubPrefix])
]);
$serializer = new Base58ExtendedKeySerializer(
new ExtendedKeySerializer($adapter, $config)
);
$path = '0/' . $index;
$fkey = $serializer->parse($btc, $key);
$child_key = $fkey->derivePath($path);
#$account0Key = $child_key->derivePath("84'/0'/0'");
#$child_key = $fkey->derivePath("0/1");
//dd($child_key->getAddress(new AddressCreator())->getAddress());
return $child_key->getAddress(new AddressCreator())->getAddress();
}
I have two problems with this code:
Problem #1
On the first few lines of the code you will see that I used an If statement to check what network should it use. On my test im using testnet network and I'm sure as well that the code on my If / else { # code } works and it uses NetworkFactory::bitcoinTestnet() and new BitcoinTestnetRegistry() properly;
$key variable represents the Master Public Key of my user from Electrum wallet or whatever with a format of (xpub#########################/vpub#########################) or in my case since its on testnet it uses tpub######################### format. However, it returns an address with a format of bc#########, this means that its passing on mainnet network wherein it should be on testnet network.
Problem #2
On lower part of my code, I'm using $fkey = $serializer->parse($btc, $key); and $child_key = $fkey->derivePath($path) wherein $path = '0/' $index. $index here are just random numbers. It can be 0/1 or 0/99 or whatever 0/random.
Problem here is that somehow related to Problem #1, after it generates the wrong address, when I try to use this address for transaction my rpc returns an invalid address Error. As you can see as well I have a commented code $account0Key = $child_key->derivePath("84'/0'/0'"); wherein i got an error that it needs a private key instead of a public one. Now, my concern is that I do not want the users of the system i'm making to put their private keys whatsoever as it will might just compromise their wallets.
Basically, What I want to achieve using with this library from BitWasp is when a user put in their master public key from their wallet, my system would be able to then generate an address to be used for a btc transaction. Please help.
Passing the network inside the getAddress() method works
return $child_key->getAddress(new AddressCreator())->getAddress($btc);

How to create an "Application Signed Request" with Sinch using PHP

I am trying to use the Sinch Rest API with PHP to mute and unmute specific participants from Conference calls but have not been able to find an example of how to send an application signed request with PHP. I have been trying to work off of this documentation from Sinch here https://www.sinch.com/docs/voice/rest/index.html#muteunmuteconfparticipant
My initial guesses are that this would require the use of CURL and that I would also need to use similar pieces of this example to sign my application but I"m not sure how to combine the two. https://github.com/sinch/php-auth-ticket
Any help appreciated. Thanks!
edit: #cjensen I added this code snippet I've been working on to try and use as the signed request maker. It's very similar to that github link above
<?php
class SinchTicketGenerator
{
private $applicationKey;
private $applicationSecret;
public function __construct($applicationKey, $applicationSecret)
{
$this->applicationKey = $applicationKey;
$this->applicationSecret = $applicationSecret;
}
public function generateTicket()
{
$request = [
'command' => 'mute',
];
$requestJson = preg_replace('/\s+/', '', json_encode($request));
$requestBase64 = $this->base64Encode($requestJson);
$digest = $this->createDigest($requestJson);
$signature = $this->base64Encode($digest);
$requestSigned = $requestBase64.':'.$signature;
return $requestSigned;
}
private function base64Encode($data)
{
return trim(base64_encode($data));
}
private function createDigest($data)
{
return trim(hash_hmac('sha256', $data, base64_decode($this->applicationSecret), true));
}
}
$generator = new SinchTicketGenerator('app-key', 'app-secret');
$signedrequest = $generator->generateTicket();
echo $signedrequest;
?>

codeigniter url encrypt not working

<a href="<?php echo base_url().'daily_report/index/'.$this->encrypt->encode($this->session->userdata('employee_id')) ?>">
i have encrypted the above url using the codeigniter encrypt
i set the encryption key in codeigniter config file
$config['encryption_key'] = 'gIoueTFDwGzbL2Bje9Bx5B0rlsD0gKDV';
and i called in the autoload
$autoload['libraries'] = array('session','form_validation','encrypt','encryption','database');
when the ulr(href) load into the url it look like this
http://localhost/hrms/daily_report/index/FVjGcz4qQztqAk0jaomJiAFBZ/vKVSBug1iGPQeKQCZ/K7+WUE4E/M9u1EjWh3uKTKeIhExjGKK1dJ2awL0+zQ==
but the url is not decoded, and i;m not getting the employee_id it shows empty.
public function index($employee_id) {
$save_employee_id = $employee_id;
// decoding the encrypted employee id
$get_employee_id = $this->encrypt->decode($save_employee_id);
echo $employee_id; // answer: FVjGcz4qQztqAk0jaomJiAFBZ
echo "<br>";
echo $get_employee_id; // is display the null
echo "<br>";
exit();
// get the employee daily report
$data['get_ind_report'] = $this->daily_report_model->get_ind_report($get_employee_id);
// daily report page
$data['header'] = "Daily Report";
$data['sub_header'] = "All";
$data['main_content'] = "daily_report/list";
$this->load->view('employeelayout/main',$data);
}
complete url(3) is
FVjGcz4qQztqAk0jaomJiAFBZ/vKVSBug1iGPQeKQCZ/K7+WUE4E/M9u1EjWh3uKTKeIhExjGKK1dJ2awL0+zQ==
it shows only
FVjGcz4qQztqAk0jaomJiAFBZ
i tried to change in the
$config['permitted_uri_chars'] = 'a-zA-Z 0-9~%.:_\-#=+';
by / in the permitted uri chars
but it throwing error
So, i need to encryption the $id in the url using the codeigniter encrypt class and decrypt in the server side to get the actual $id, So that i fetch data from the DB. any help would be appreciated
You have to extend encryption class and avoid the / to get it working. Place this class in your application/libraries folder. and name it as MY_Encrypt.php.
class MY_Encrypt extends CI_Encrypt
{
/**
* Encodes a string.
*
* #param string $string The string to encrypt.
* #param string $key[optional] The key to encrypt with.
* #param bool $url_safe[optional] Specifies whether or not the
* returned string should be url-safe.
* #return string
*/
function encode($string, $key="", $url_safe=TRUE)
{
$ret = parent::encode($string, $key);
if ($url_safe)
{
$ret = strtr(
$ret,
array(
'+' => '.',
'=' => '-',
'/' => '~'
)
);
}
return $ret;
}
/**
* Decodes the given string.
*
* #access public
* #param string $string The encrypted string to decrypt.
* #param string $key[optional] The key to use for decryption.
* #return string
*/
function decode($string, $key="")
{
$string = strtr(
$string,
array(
'.' => '+',
'-' => '=',
'~' => '/'
)
);
return parent::decode($string, $key);
}
}
FVjGcz4qQztqAk0jaomJiAFBZ/vKVSBug1iGPQeKQCZ/K7+WUE4E/M9u1EjWh3uKTKeIhExjGKK1dJ2awL0+zQ==
Shows
FVjGcz4qQztqAk0jaomJiAFBZ
If you look at your url closely, you could see that after the result which has been shown there is a '/' . Now any string after that will be treated as another segment. Hence it could not decode.
The encrypt library in this case would not work.
Either you stop passing that through the URL or use another different technique base_encode().
Hope that helps
This is happening as the character "/" is part of html uri delimiter. Instead you can work around it by avoiding that character in html url by rawurlencoding your encrytion output string before attaching it to url.
\edit:
I tried rawurlencode, but wasn't able to get the proper output.
Finally succeeded by using this code.
Define two functions:
function hex2str( $hex ) {
return pack('H*', $hex);
}
function str2hex( $str ) {
return array_shift( unpack('H*', $str) );
}
Then use call str2hex and pass it the encrypted user id to convert encrypted string into hexcode.
Reverse the process to get the correct string so that you can decrypt it.
I was able to properly encode and decode:
"FVjGcz4qQztqAk0jaomJiAFBZ/vKVSBug1iGPQeKQCZ/K7+WUE4E/M9u1EjWh3uKTKeIhExjGKK1dJ2awL0+zQ=="
to:
"46566a47637a3471517a7471416b306a616f6d4a694146425a2f764b56534275673169475051654b51435a2f4b372b57554534452f4d397531456a576833754b544b65496845786a474b4b31644a3261774c302b7a513d3d"
The url would become rather long though.

Signed URL for google bucket does not match signature provided

I'm having an hard time working with google storage.
So I'm trying to make a signed url, already have the client id (which is an email) and private key (as described here) so:
STEP 1: construct the string
function googleBuildConfigurationString($method, $expiration, $file, array $options = []) {
$allowedMethods = ['GET', 'HEAD', 'PUT', 'DELETE'];
// initialize
$method = strtoupper($method);
$contentType = $options['Content_Type'];
$contentMd5 = $options['Content_MD5'] ? base64_encode($options['Content_MD5']) : '';
$headers = $options['Canonicalized_Extension_Headers'] ? $options['Canonicalized_Extension_Headers'] . PHP_EOL : '';
$file = $file ? $file : $options['Canonicalized_Resource'];
// validate
if(array_search($method, $allowedMethods) === false) {
throw new RuntimeException("Method '{$method}' is not allowed");
}
if(!$expiration) {
throw new RuntimeException("An expiration date should be provided.");
}
return <<<TXT
{$method}
{$contentMd5}
{$contentType}
{$expiration}
{$headers}{$file}
TXT;
}
So far so good (I think), echoing the output it looks similar to the examples, so now to sign the string
STEP 2: signing the string
Initialy I was using openssl_public_encrypt, after searching around found that google-api-php-client has the Google_Signer_P12 (which actually uses openssl_sign), so the method looks like:
function googleSignString($certificatePath, $stringToSign) {
return (new Google_Signer_P12(
file_get_contents($certificatePath),
'notasecret'
))->sign($stringToSign);
}
And here I'm not sure if this is signing it correctly, finally building final url
STEP 3: building the URL
function googleBuildSignedUrl($serviceEmail, $file, $expiration, $signature) {
return "http://storage.googleapis.com{$file}"
. "?GoogleAccessId={$serviceEmail}"
. "&Expires={$expiration}"
. "&Signature=" . urlencode($signature);
}
But the opening the URL in the browser will retrieve:
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
</Message>
<StringToSign>GET 1437470250 /example/video.mp4</StringToSign>
</Error>
I've added a gist with the final script to be easier to read
So any idea what am I doing wrong?
I've found the solution, there was a bug on the expiration date where I was doing:
$expiration = (new DateTime())->modify('+3h')->getTimestamp();
So I've changed h to hours so that it works now, like:
$expiration = (new DateTime())->modify('+3hours')->getTimestamp();
But that didn't quite solved it, the actual missing part is that the Google_Signer_P12::sign() requires it to be encoded on base64, which is specified on the google docs:
Google Cloud Storage expects the Base64 encoded signature in its APIs.
However I (wrongly) though that Google_Signer_P12::sign() already would do that, so after I understood that it was required I've changed the sign method to:
function googleSignString($certificatePath, $stringToSign)
{
return base64_encode((new Google_Signer_P12(
file_get_contents($certificatePath),
'notasecret'
))->sign($stringToSign));
}
And it is working now!!!
I've also updated the gist for anyone that wants to use it :)

Sage One API Error

I am using the SageOne API PHP Library. It works fine, but I get an error if I try to use get or post.
The error is,
Only variables should be passed by reference sage.api.php on line 130
My get request code is
$client = new SageOne(SAGE_CLIENT_ID, SAGE_CLIENT_SECRET);
$client->setAccessToken("c7c7547xxxxxxxxxxxx8efa4f5df08f750df");
$data = array( );
$result = "";
$client = $client->get('/products', $data);
I don’t know what’s wrong.
Full Code
require 'sage.api.php';
define('SAGE_CLIENT_ID', "fa1e8c1b114347a356d2");
define('SAGE_CLIENT_SECRET', "faaa7b353521f823ba13e3a20e72dd057c3a5fd1");
$client = new SageOne(SAGE_CLIENT_ID, SAGE_CLIENT_SECRET);
$callbackURL = 'xxxxx/addonmodules.php?module=sageone';
// We need to build the authorise url and redirect user to authorise our app
if(!$_GET['code']){
$authoriseURL = $client->getAuthoriseURL($callbackURL);
// redirect user
header("Location: ".$authoriseURL);
exit;
// We now have the authorisation code to retrieve the access token
} else {
$accessToken = $client->getAccessToken($_GET['code'], $callbackURL);
$token= $accessToken['access_token'];
$end = 'public';
$data ='';
$result = $client->get($end, $data);
echo '<pre>';
print_r($result);
Code Snippets from sage.api.php
class SageOne { ...
...
public function get($endpoint, $data=false){
return $this->call($endpoint, 'get', $data);
}
...
// error line 130 from this code
private function buildSignature($method, $url, $params, $nonce){
// uc method and append &
$signature = strtoupper($method).'&';
// percent encode bit of url before ? and append &
$signature .= rawurlencode(array_shift(explode('?', $url))).'&';
// percent encode any params and append &
if (is_array($params)){
// sort params alphabetically
$this->ksortRecursive($params);
// build query string from params, encode it and append &
$signature .= str_replace(
array('%2B'),
array('%2520'),
rawurlencode(http_build_query($params, '', '&'))
).'&';
// params can be string
} else {
// build query string from params, encode it and append &
$signature .= rawurlencode($params).'&';
}
// add 'nonce' - just use an md5
$signature .= $nonce;
// now generate signing key
$signingKey = rawurlencode($this->signingSecret).'&'.rawurlencode($this->accessToken);
// encode using sha 1, then base64 encode
$finalSignature = base64_encode(hash_hmac('sha1', $signature, $signingKey, true));
return $finalSignature;
}
This is the shortest i can make to see all important code
This is due to trying to return the result of a function or method directly to another function or method... the result doesn't have a reference.
So, for example:
$obj->method(doSomething(), 'asdf', 'qwerty');
The error means you should assign the value of doSomething() before passing it.
$result = doSomething();
$obj->method($result, 'asdf', 'qwerty');
Also see: Only variables should be passed by reference
A function (in this case, $client->get()) can be defined to receive its parameters by reference. This means that it can modify those parameters directly. So if you call $client->get($a, $b), the function may alter the values of $a and $b.
Clearly, it can only alter the values of variables, so when a function receives a parameter by reference, you must pass it a variable, not a string, an integer, or a direct call to another function.
So if the function $client->get() receives its first parameter by reference, none of the following can work:
$client->get('string', $data);
$client->get(15, $data); // int
$client->get(other_function_call(), $data);
$client->get(12.5, $data); // float
$client->get(array(), $data);
You have to do this:
$a = 'string';
$client->get($a, $data);
Or $a = whatever, be it a string, an int, a function call. The point is (and this is stated quite clearly in the error message) that you must pass a variable. So save whatever you want to pass as a variable, then pass that.

Categories