Skip to content

Commit

Permalink
bugfix: fix sas token redaction
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewhilton committed Oct 31, 2024
1 parent dc631e6 commit fdf2665
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 19 deletions.
46 changes: 33 additions & 13 deletions classes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use GuzzleHttp\Psr7\Request;
use Psr\Http\Message\StreamInterface;
use coding_exception;
use GuzzleHttp\Exception\RequestException;

/**
* Azure blob storage API.
Expand Down Expand Up @@ -76,14 +77,17 @@ class api {
* @param string $account Azure storage account name
* @param string $container Azure storage container name (inside the given storage account).
* @param string $sastoken SAS (Shared access secret) token for authentication.
* @param bool $redactsastoken If should react SAS token from error messages to avoid accidental leakage.
*/
public function __construct(
/** @var string Azure storage account name */
public readonly string $account,
public string $account,
/** @var string Azure storage container name */
public readonly string $container,
public string $container,
/** @var string SAS token for authentication */
public readonly string $sastoken
public string $sastoken,
/** @var bool If should redact SAS token from error messages to avoid accidental leakage */
public bool $redactsastoken = true
) {
$this->client = new Client();
}
Expand Down Expand Up @@ -133,7 +137,8 @@ private function build_blob_properties_url(string $blobkey): string {
*/
public function get_blob_async(string $key): PromiseInterface {
// Enable streaming response, useful for large files e.g. videos.
return $this->client->getAsync($this->build_blob_url($key), ['stream' => true]);
return $this->client->getAsync($this->build_blob_url($key), ['stream' => true])
->then(null, $this->clean_exception_sas_if_needed());
}

/**
Expand All @@ -142,7 +147,7 @@ public function get_blob_async(string $key): PromiseInterface {
* @return PromiseInterface Promise that resolves a ResponseInterface value where the properties are in the response headers.
*/
public function get_blob_properties_async(string $key): PromiseInterface {
return $this->client->headAsync($this->build_blob_url($key));
return $this->client->headAsync($this->build_blob_url($key))->then(null, $this->clean_exception_sas_if_needed());
}

/**
Expand All @@ -151,7 +156,7 @@ public function get_blob_properties_async(string $key): PromiseInterface {
* @return PromiseInterface Promise that resolves once the delete request succeeds.
*/
public function delete_blob_async(string $key): PromiseInterface {
return $this->client->deleteAsync($this->build_blob_url($key));
return $this->client->deleteAsync($this->build_blob_url($key))->then(null, $this->clean_exception_sas_if_needed());
}

/**
Expand Down Expand Up @@ -194,7 +199,7 @@ public function put_blob_single_async(string $key, StreamInterface $contentstrea
],
'body' => $contentstream,
]
);
)->then(null, $this->clean_exception_sas_if_needed());
}

/**
Expand Down Expand Up @@ -222,22 +227,22 @@ public function put_blob_multipart_async(string $key, StreamInterface $contentst
while (true) {
$content = $contentstream->read(self::MULTIPART_BLOCK_SIZE);

// Each block has its own md5 specific to itself.
$blockmd5 = base64_encode(hex2bin(md5($content)));

// Finished reading, nothing more to upload.
if (empty($content)) {
break;
}

// Each block has its own md5 specific to itself.
$blockmd5 = base64_encode(hex2bin(md5($content)));

// The block ID must be the same length regardles of the counter value.
// So pad them with zeros.
$blockid = base64_encode(
str_pad($counter++, 6, '0', STR_PAD_LEFT)
);

$request = new Request('PUT', $this->build_blob_block_url($key, $blockid), ['content-md5' => $blockmd5], $content);
$promises[] = $this->client->sendAsync($request);
$promises[] = $this->client->sendAsync($request)->then(null, $this->clean_exception_sas_if_needed());
$blockids[] = $blockid;
};

Expand All @@ -253,14 +258,14 @@ public function put_blob_multipart_async(string $key, StreamInterface $contentst
$bodymd5 = base64_encode(hex2bin(md5($body)));
$request = new Request('PUT', $this->build_blocklist_url($key),
['Content-Type' => 'application/xml', 'content-md5' => $bodymd5], $body);
$this->client->send($request);
$this->client->sendAsync($request)->then(null, $this->clean_exception_sas_if_needed())->wait();

// Now it is combined, set the md5 and content type on the completed blob.
$request = new Request('PUT', $this->build_blob_properties_url($key), [
'x-ms-blob-content-md5' => base64_encode($md5),
'x-ms-blob-content-type' => $contenttype,
]);
$this->client->send($request);
$this->client->sendAsync($request)->then(null, $this->clean_exception_sas_if_needed())->wait();

// Done, resolve the entire promise.
$entirepromise->resolve('fulfilled');
Expand Down Expand Up @@ -294,4 +299,19 @@ private function make_block_list_xml(array $blockidlist): string {
$string .= "\n</BlockList>";
return $string;
}

/**
* Returns a request exception handling function that redacts the SAS token from error messages if needed.
* @return callable
*/
private function clean_exception_sas_if_needed(): callable {
return function(RequestException $ex) {
if ($this->redactsastoken) {
$newmsg = str_replace($this->sastoken, '[SAS TOKEN REDACTED]', $ex->getMessage());
$exceptiontype = get_class($ex);
throw new $exceptiontype($newmsg, $ex->getRequest(), $ex->getResponse(), $ex, $ex->getHandlerContext());
}
throw $ex;
};
}
}
6 changes: 2 additions & 4 deletions classes/stream_wrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,10 @@ public function stream_seek($offset, $whence = SEEK_SET) {

/**
* Returns current position of stream.
* @return bool
* @return int
*/
public function stream_tell() {
return $this->boolCall(function() {
return $this->body->tell();
});
return $this->body->tell();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions version.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

$plugin->version = 2024101400; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = 2024101400; // Same as version.
$plugin->requires = 2024042200; // 4.4.0, PHP 8.1.0+
$plugin->requires = 2023042400; // 4.2.0, PHP 8.0.0+
$plugin->component = "local_azureblobstorage";
$plugin->maturity = MATURITY_ALPHA;
$plugin->supported = [404, 405];
$plugin->supported = [402, 405];

0 comments on commit fdf2665

Please sign in to comment.