diff --git a/third_party/astrolabe/lib/Service/IdpTokenRefresher.php b/third_party/astrolabe/lib/Service/IdpTokenRefresher.php index d57e051..4ef5fab 100644 --- a/third_party/astrolabe/lib/Service/IdpTokenRefresher.php +++ b/third_party/astrolabe/lib/Service/IdpTokenRefresher.php @@ -38,25 +38,19 @@ class IdpTokenRefresher { /** * Get Nextcloud base URL for constructing internal OIDC endpoint URLs. * - * @return string Base URL (e.g., "https://nextcloud.example.com") + * IMPORTANT: This method returns the INTERNAL URL for server-to-server + * requests within the container. External URLs (like localhost:8080) won't + * work from inside the container since localhost refers to the container itself. + * + * For internal requests, we always use http://localhost (port 80) since + * Nextcloud's web server is accessible at that address inside the container. + * + * @return string Base URL for internal requests (e.g., "http://localhost") */ private function getNextcloudBaseUrl(): string { - // Prefer explicit CLI URL override - $baseUrl = $this->config->getSystemValue('overwrite.cli.url', ''); - - if (!empty($baseUrl)) { - return rtrim($baseUrl, '/'); - } - - // Fallback to first trusted domain with protocol - $trustedDomains = $this->config->getSystemValue('trusted_domains', []); - if (!empty($trustedDomains)) { - $protocol = $this->config->getSystemValue('overwriteprotocol', 'https'); - return $protocol . '://' . $trustedDomains[0]; - } - - // Last resort: localhost (log warning) - $this->logger->warning('IdpTokenRefresher: No Nextcloud URL configured, using localhost fallback'); + // For internal requests within the container, always use http://localhost + // The web server is accessible at port 80 inside the container. + // External URLs like http://localhost:8080 won't work from inside the container. return 'http://localhost'; } diff --git a/third_party/astrolabe/lib/Settings/Personal.php b/third_party/astrolabe/lib/Settings/Personal.php index 577f1e8..6a453b3 100644 --- a/third_party/astrolabe/lib/Settings/Personal.php +++ b/third_party/astrolabe/lib/Settings/Personal.php @@ -79,60 +79,48 @@ class Personal implements ISettings { // Check if user has MCP OAuth token $token = $this->tokenStorage->getUserToken($userId); - // For multi_user_basic mode with app password support, check if user has app password + // For multi_user_basic mode with app password support (hybrid mode) + // User needs BOTH: + // 1. OAuth token for Astrolabe→MCP API calls (stored in McpTokenStorage) + // 2. App password for MCP→Nextcloud background sync if ($authMode === 'multi_user_basic' && $supportsAppPasswords) { - // Check if user has already provided an app password - $hasBackgroundAccess = $this->tokenStorage->hasBackgroundSyncAccess($userId); + // Check both credentials + $hasOAuthToken = ($token !== null && !$this->tokenStorage->isExpired($token)); + $hasAppPassword = $this->tokenStorage->hasBackgroundSyncAccess($userId); + $backgroundSyncType = $this->tokenStorage->getBackgroundSyncType($userId); + $backgroundSyncProvisionedAt = $this->tokenStorage->getBackgroundSyncProvisionedAt($userId); - if (!$hasBackgroundAccess) { - // No app password yet - show app password entry form - return new TemplateResponse( - Application::APP_ID, - 'settings/personal', - [ - 'serverUrl' => $this->client->getPublicServerUrl(), // Changed from server_url to serverUrl - 'serverStatus' => $serverStatus, - 'auth_mode' => $authMode, - 'authMode' => $authMode, // Add camelCase version for template - 'supports_app_passwords' => $supportsAppPasswords, - 'supportsAppPasswords' => $supportsAppPasswords, // Add camelCase version - 'session' => null, // No session yet - 'hasBackgroundAccess' => false, // FIXED: Add missing parameter - 'backgroundAccessGranted' => false, // FIXED: Add missing parameter - 'vectorSyncEnabled' => $serverStatus['vector_sync_enabled'] ?? false, - 'hasToken' => false, // No OAuth token in multi_user_basic mode - 'requesttoken' => \OCP\Util::callRegister(), - ], - TemplateResponse::RENDER_AS_BLANK - ); - } else { - // User has app password - show active status - $backgroundSyncType = $this->tokenStorage->getBackgroundSyncType($userId); - $backgroundSyncProvisionedAt = $this->tokenStorage->getBackgroundSyncProvisionedAt($userId); + // OAuth URL for Astrolabe's own OAuth controller (NOT MCP server's browser OAuth) + $oauthUrl = $this->urlGenerator->linkToRoute('astrolabe.oauth.initiateOAuth'); - $parameters = [ - 'userId' => $userId, - 'serverStatus' => $serverStatus, - 'session' => null, // No user session for app passwords - 'vectorSyncEnabled' => $serverStatus['vector_sync_enabled'] ?? false, - 'backgroundAccessGranted' => true, // App password grants background access - 'serverUrl' => $this->client->getPublicServerUrl(), - 'hasToken' => false, // No OAuth token - 'hasBackgroundAccess' => true, - 'backgroundSyncType' => $backgroundSyncType, - 'backgroundSyncProvisionedAt' => $backgroundSyncProvisionedAt, - 'authMode' => $authMode, - 'supportsAppPasswords' => $supportsAppPasswords, - 'requesttoken' => \OCP\Util::callRegister(), - ]; + $parameters = [ + 'userId' => $userId, + 'serverUrl' => $this->client->getPublicServerUrl(), + 'serverStatus' => $serverStatus, + 'auth_mode' => $authMode, + 'authMode' => $authMode, + 'supports_app_passwords' => $supportsAppPasswords, + 'supportsAppPasswords' => $supportsAppPasswords, + 'session' => null, // No session in hybrid mode + 'vectorSyncEnabled' => $serverStatus['vector_sync_enabled'] ?? false, + // OAuth token status (for Astrolabe→MCP API calls) + 'hasToken' => $hasOAuthToken, + 'hasOAuthToken' => $hasOAuthToken, + 'oauthUrl' => $oauthUrl, + // App password status (for MCP→Nextcloud background sync) + 'hasBackgroundAccess' => $hasAppPassword, + 'backgroundAccessGranted' => $hasAppPassword, + 'backgroundSyncType' => $backgroundSyncType, + 'backgroundSyncProvisionedAt' => $backgroundSyncProvisionedAt, + 'requesttoken' => \OCP\Util::callRegister(), + ]; - return new TemplateResponse( - Application::APP_ID, - 'settings/personal', - $parameters, - TemplateResponse::RENDER_AS_BLANK - ); - } + return new TemplateResponse( + Application::APP_ID, + 'settings/personal', + $parameters, + TemplateResponse::RENDER_AS_BLANK + ); } // For OAuth modes, if no token or token is expired, show OAuth authorization UI elseif (!$token || $this->tokenStorage->isExpired($token)) { diff --git a/third_party/astrolabe/templates/settings/personal.php b/third_party/astrolabe/templates/settings/personal.php index f4738be..2d4811d 100644 --- a/third_party/astrolabe/templates/settings/personal.php +++ b/third_party/astrolabe/templates/settings/personal.php @@ -43,7 +43,17 @@ style('astrolabe', 'astrolabe-personalSettings');
@@ -110,54 +120,129 @@ style('astrolabe', 'astrolabe-personalSettings');
- t('Enable background sync to allow the MCP server to access your Nextcloud data for background operations like content indexing.')); ?> -
- -- t('When Nextcloud fully supports OAuth for app APIs. Currently waiting for upstream PR to merge.')); ?> -
- - - t('Authorize via OAuth')); ?> - -- t('Generate an app password in Security settings and provide it below. This is the recommended interim solution.')); ?> + t('To use semantic search, you need to complete two setup steps:')); ?>
-t('Step 1:')); ?>
-
- t('Generate app password in Security settings')); ?>
+
+
+ t('Authorize Astrolabe to perform searches on your behalf.')); ?>
+ t('Search access authorized.')); ?>
+ t('Provide an app password to allow background indexing of your content.')); ?>
+ t('Background indexing enabled.')); ?>
+ t('Enable background sync to allow the MCP server to access your Nextcloud data for background operations like content indexing.')); ?>
+
+ t('When Nextcloud fully supports OAuth for app APIs. Currently waiting for upstream PR to merge.')); ?>
+
+ t('Generate an app password in Security settings and provide it below. This is the recommended interim solution.')); ?>
t('Step 2:')); ?> t('Enter the app password below:')); ?>
+
+ t('Complete')); ?>
+
+ t('Required')); ?>
+
+ t('Step 1: Authorize Search Access')); ?>
+
+
+
+ t('Complete')); ?>
+
+ t('Required')); ?>
+
+ t('Step 2: Enable Background Indexing')); ?>
+
+ t('Option 1: OAuth Refresh Token (Recommended for Future)')); ?>
+ t('Option 2: App Password (Works Today - Recommended)')); ?>
+