aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Module/Owa.php184
-rw-r--r--tests/unit/Module/OwaTest.php64
2 files changed, 170 insertions, 78 deletions
diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php
index 85467d4f4..21082e166 100644
--- a/Zotlabs/Module/Owa.php
+++ b/Zotlabs/Module/Owa.php
@@ -18,96 +18,95 @@ use Zotlabs\Web\Controller;
class Owa extends Controller {
- function init() {
+ public function init(): void
+ {
$ret = [ 'success' => false ];
- if (array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) {
- $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER'];
+ if (!$this->validateAuthorizationHeader()) {
+ $this->error('Missing or invalid authorization header.');
}
- if (array_key_exists('HTTP_AUTHORIZATION',$_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') {
- $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
- if ($sigblock) {
- $keyId = $sigblock['keyId'];
- $parsed = parse_url($keyId);
- if (str_starts_with($parsed['scheme'],'http')) {
- unset($parsed['fragment']);
- unset($parsed['query']);
- $keyId = unparse_url($parsed);
- }
- else {
- $keyId = str_replace('acct:', '', $keyId);
+ $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']);
+ if ($sigblock) {
+ $keyId = $sigblock['keyId'];
+ $parsed = parse_url($keyId);
+ if (str_starts_with($parsed['scheme'],'http')) {
+ unset($parsed['fragment']);
+ unset($parsed['query']);
+ $keyId = unparse_url($parsed);
+ }
+ else {
+ $keyId = str_replace('acct:', '', $keyId);
+ }
+ if ($keyId) {
+ $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
+ WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
+ AND hubloc_deleted = 0 AND xchan_pubkey != ''
+ ORDER BY hubloc_id DESC",
+ dbesc($keyId),
+ dbesc($keyId),
+ dbesc($keyId)
+ );
+ if (! $r) {
+ $found = discover_by_webbie($keyId);
+ logger('found = ' . print_r($found, true));
+ if ($found) {
+ $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
+ WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
+ dbesc($keyId),
+ dbesc($keyId),
+ dbesc($keyId)
+ );
+ }
}
- if ($keyId) {
- $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
- WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s')
- AND hubloc_deleted = 0 AND xchan_pubkey != ''
- ORDER BY hubloc_id DESC",
- dbesc($keyId),
- dbesc($keyId),
- dbesc($keyId)
- );
- if (! $r) {
+
+ if ($r) {
+ foreach ($r as $hubloc) {
+ $verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
+ if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
+ logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
+ logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
+ $ret['success'] = true;
+ $token = random_string(32);
+ Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
+ $result = '';
+ openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
+ $ret['encrypted_token'] = base64url_encode($result);
+ break;
+ } else {
+ logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
+ }
+ }
+
+ if (!$ret['success']) {
+
+ // Possible a reinstall?
+ // In this case we probably already have an old hubloc
+ // but not the new one yet.
+
$found = discover_by_webbie($keyId);
- logger('found = ' . print_r($found, true));
+
if ($found) {
$r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
- WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s' OR xchan_hash = '%s') AND hubloc_deleted = 0 AND xchan_pubkey != '' ORDER BY hubloc_id DESC ",
- dbesc($keyId),
- dbesc($keyId),
+ WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
+ dbesc(str_replace('acct:', '', $keyId)),
dbesc($keyId)
);
- }
- }
-
- if ($r) {
- foreach ($r as $hubloc) {
- $verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
- if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
- logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
- logger('OWA success: ' . $hubloc['hubloc_id_url'],LOGGER_DATA);
- $ret['success'] = true;
- $token = random_string(32);
- Verify::create('owt',0,$token,$hubloc['hubloc_id_url']);
- $result = '';
- openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
- $ret['encrypted_token'] = base64url_encode($result);
- break;
- } else {
- logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
- }
- }
- if (!$ret['success']) {
-
- // Possible a reinstall?
- // In this case we probably already have an old hubloc
- // but not the new one yet.
-
- $found = discover_by_webbie($keyId);
-
- if ($found) {
- $r = q("SELECT * FROM hubloc LEFT JOIN xchan ON hubloc_hash = xchan_hash
- WHERE (hubloc_addr = '%s' OR hubloc_id_url = '%s') AND hubloc_deleted = 0 ORDER BY hubloc_id DESC LIMIT 1",
- dbesc(str_replace('acct:', '', $keyId)),
- dbesc($keyId)
- );
-
- if ($r) {
- $verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
- if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
- logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
- logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
- $ret['success'] = true;
- $token = random_string(32);
- Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
- $result = '';
- openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
- $ret['encrypted_token'] = base64url_encode($result);
- } else {
- logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
- }
+ if ($r) {
+ $verified = HTTPSig::verify(file_get_contents('php://input'), $r[0]['xchan_pubkey']);
+ if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
+ logger('OWA header: ' . print_r($verified,true), LOGGER_DATA);
+ logger('OWA success: ' . $r[0]['hubloc_id_url'], LOGGER_DATA);
+ $ret['success'] = true;
+ $token = random_string(32);
+ Verify::create('owt', 0, $token, $r[0]['hubloc_id_url']);
+ $result = '';
+ openssl_public_encrypt($token, $result, $r[0]['xchan_pubkey']);
+ $ret['encrypted_token'] = base64url_encode($result);
+ } else {
+ logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_id_url']);
}
}
}
@@ -118,4 +117,33 @@ class Owa extends Controller {
json_return_and_die($ret,'application/x-zot+json');
}
+
+ private function validateAuthorizationHeader(): bool
+ {
+ if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
+ $auth = trim($_SERVER['HTTP_AUTHORIZATION']);
+ } else if (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
+ $auth = trim($_SERVER['REDIRECT_REMOTE_USER']);
+ } else {
+ return false;
+ }
+
+ return strncmp($auth, 'Signature', 9) === 0;
+ }
+
+ /**
+ * Terminates the request, and return a json error response.
+ *
+ * @Note This function does not return!
+ *
+ * @param string $msg The error message for the response.
+ */
+ private function error(string $msg): void {
+ $ret = [
+ 'success' => false,
+ 'message' => $msg
+ ];
+
+ json_return_and_die($ret,'application/x-zot+json');
+ }
}
diff --git a/tests/unit/Module/OwaTest.php b/tests/unit/Module/OwaTest.php
new file mode 100644
index 000000000..dbb25c0b5
--- /dev/null
+++ b/tests/unit/Module/OwaTest.php
@@ -0,0 +1,64 @@
+<?php
+/*
+ * SPDX-FileCopyrightText: 2025 Hubzilla Community
+ * SPDX-FileContributor: Harald Eilertsen
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+namespace Zotlabs\Tests\Unit\Module;
+
+class OwaTest extends TestCase
+{
+ public function testShouldReturnErrorIfNoAuthorizationHeader(): void
+ {
+ // Expect the call to return error
+ $this->expectJsonResponse([
+ 'success' => false,
+ 'message' => 'Missing or invalid authorization header.'
+ ]);
+
+ $this->get('owa');
+ }
+
+ public function testShouldReturnErrorIfWrongAuthorizationHeader(): void
+ {
+ // Expect the call to return error
+ $this->expectJsonResponse([
+ 'success' => false,
+ 'message' => 'Missing or invalid authorization header.'
+ ]);
+
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Bearer kjkjhkjhkjh';
+ $this->get('owa');
+ }
+
+ public function testShouldReturnErrorIfInvalidAuthorizationHeader(): void
+ {
+ // Expect the call to return error
+ $this->expectJsonResponse(['success' => false]);
+
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Signature kjkjhkjhkjh';
+ $this->get('owa');
+ }
+
+ /**
+ * Expect the request to be terminated and return a json response.
+ */
+ private function expectJsonResponse(array $data): void
+ {
+ $this->getFunctionMock('Zotlabs\Module', 'json_return_and_die')
+ ->expects($this->once())
+ ->with(
+ $this->identicalTo($data),
+ $this->identicalTo('application/x-zot+json')
+ )
+ ->willReturnCallback(
+ function() {
+ throw new KillmeException();
+ }
+ );
+
+ $this->expectException(KillmeException::class);
+ }
+}