@fleetbase/solid-engine 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ACL_SOLUTION.md +72 -0
- package/CSS_SCOPE_ISSUE.md +140 -0
- package/HOTFIX_SYNTAX_ERROR.md +100 -0
- package/MANUAL_ACL_SETUP.md +135 -0
- package/REFACTORING_SUMMARY.md +330 -0
- package/VERIFICATION_CHECKLIST.md +82 -0
- package/addon/components/modals/create-solid-folder.hbs +29 -0
- package/addon/components/modals/import-solid-resources.hbs +85 -0
- package/addon/controllers/data/content.js +17 -0
- package/addon/controllers/data/index.js +219 -0
- package/addon/controllers/home.js +84 -0
- package/addon/engine.js +1 -24
- package/addon/extension.js +26 -0
- package/addon/routes/data/content.js +11 -0
- package/addon/routes/data/index.js +17 -0
- package/addon/routes.js +2 -7
- package/addon/styles/solid-engine.css +1 -2
- package/addon/templates/account.hbs +3 -3
- package/addon/templates/application.hbs +2 -12
- package/addon/templates/data/content.hbs +48 -0
- package/addon/templates/{pods/explorer.hbs → data/index.hbs} +6 -5
- package/addon/templates/home.hbs +168 -10
- package/app/components/modals/{backup-pod.js → create-solid-folder.js} +1 -1
- package/app/components/modals/{resync-pod.js → import-solid-resources.js} +1 -1
- package/app/components/modals/{create-pod.js → setup-css-credentials.js} +1 -1
- package/composer.json +4 -10
- package/extension.json +1 -1
- package/index.js +0 -11
- package/package.json +8 -8
- package/server/migrations/2024_12_21_add_css_credentials_to_solid_identities_table.php +32 -0
- package/server/src/Client/OpenIDConnectClient.php +686 -15
- package/server/src/Client/SolidClient.php +104 -8
- package/server/src/Http/Controllers/DataController.php +261 -0
- package/server/src/Http/Controllers/OIDCController.php +42 -8
- package/server/src/Http/Controllers/SolidController.php +179 -85
- package/server/src/Models/SolidIdentity.php +13 -3
- package/server/src/Services/AclService.php +146 -0
- package/server/src/Services/PodService.php +863 -0
- package/server/src/Services/ResourceSyncService.php +336 -0
- package/server/src/Services/VehicleSyncService.php +289 -0
- package/server/src/Support/Utils.php +10 -0
- package/server/src/routes.php +25 -1
- package/addon/components/modals/backup-pod.hbs +0 -3
- package/addon/components/modals/create-pod.hbs +0 -5
- package/addon/components/modals/resync-pod.hbs +0 -3
- package/addon/controllers/pods/explorer/content.js +0 -12
- package/addon/controllers/pods/explorer.js +0 -149
- package/addon/controllers/pods/index/pod.js +0 -12
- package/addon/controllers/pods/index.js +0 -137
- package/addon/routes/pods/explorer/content.js +0 -10
- package/addon/routes/pods/explorer.js +0 -44
- package/addon/routes/pods/index/pod.js +0 -3
- package/addon/routes/pods/index.js +0 -21
- package/addon/templates/pods/explorer/content.hbs +0 -19
- package/addon/templates/pods/index/pod.hbs +0 -11
- package/addon/templates/pods/index.hbs +0 -19
- package/server/src/LegacyClient/Identity/IdentityProvider.php +0 -174
- package/server/src/LegacyClient/Identity/Profile.php +0 -18
- package/server/src/LegacyClient/OIDCClient.php +0 -350
- package/server/src/LegacyClient/Profile/WebID.php +0 -26
- package/server/src/LegacyClient/SolidClient.php +0 -271
|
@@ -5,6 +5,7 @@ namespace Fleetbase\Solid\Client;
|
|
|
5
5
|
use Fleetbase\Solid\Models\SolidIdentity;
|
|
6
6
|
use Illuminate\Http\Client\Response;
|
|
7
7
|
use Illuminate\Support\Facades\Http;
|
|
8
|
+
use Illuminate\Support\Facades\Log;
|
|
8
9
|
use Illuminate\Support\Str;
|
|
9
10
|
|
|
10
11
|
class SolidClient
|
|
@@ -12,8 +13,8 @@ class SolidClient
|
|
|
12
13
|
private string $host = 'localhost';
|
|
13
14
|
private int $port = 3000;
|
|
14
15
|
private bool $secure = true;
|
|
15
|
-
public
|
|
16
|
-
public
|
|
16
|
+
public SolidIdentity $identity;
|
|
17
|
+
public OpenIDConnectClient $oidc;
|
|
17
18
|
private const DEFAULT_MIME_TYPE = 'text/turtle';
|
|
18
19
|
private const LDP_BASIC_CONTAINER = 'http://www.w3.org/ns/ldp#BasicContainer';
|
|
19
20
|
private const LDP_RESOURCE = 'http://www.w3.org/ns/ldp#Resource';
|
|
@@ -95,6 +96,23 @@ class SolidClient
|
|
|
95
96
|
return $this;
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Make a request with a specific identity.
|
|
101
|
+
*/
|
|
102
|
+
public function requestWithIdentity(SolidIdentity $identity, string $method, string $uri, string|array $data = [], array $options = []): Response
|
|
103
|
+
{
|
|
104
|
+
$this->identity = $identity;
|
|
105
|
+
|
|
106
|
+
// Check if we should skip authentication
|
|
107
|
+
$withoutAuth = data_get($options, 'withoutAuth', false);
|
|
108
|
+
|
|
109
|
+
if ($withoutAuth) {
|
|
110
|
+
return $this->request($method, $uri, $data, $options);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return $this->authenticatedRequest($method, $uri, $data, $options);
|
|
114
|
+
}
|
|
115
|
+
|
|
98
116
|
/**
|
|
99
117
|
* Make a HTTP request to the Solid server.
|
|
100
118
|
*
|
|
@@ -102,17 +120,27 @@ class SolidClient
|
|
|
102
120
|
* @param string $uri The URI to send the request to
|
|
103
121
|
* @param array $options Options for the request
|
|
104
122
|
*/
|
|
105
|
-
protected function request(string $method, string $uri, array $data = [], array $options = []): Response
|
|
123
|
+
protected function request(string $method, string $uri, string|array $data = [], array $options = []): Response
|
|
106
124
|
{
|
|
107
125
|
$url = $this->createRequestUrl($uri);
|
|
108
126
|
|
|
109
|
-
|
|
127
|
+
// For development: disable SSL verification when using HTTPS
|
|
128
|
+
if ($this->secure && app()->environment('local', 'development')) {
|
|
129
|
+
$options['verify'] = false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Handle different data types
|
|
133
|
+
if (is_string($data)) {
|
|
134
|
+
return Http::withOptions($options)->withBody($data, $options['headers']['Content-Type'] ?? 'text/plain')->send($method, $url);
|
|
135
|
+
} else {
|
|
136
|
+
return Http::withOptions($options)->{$method}($url, $data);
|
|
137
|
+
}
|
|
110
138
|
}
|
|
111
139
|
|
|
112
140
|
/**
|
|
113
141
|
* Send an authenticated request with the current identity.
|
|
114
142
|
*/
|
|
115
|
-
public function authenticatedRequest(string $method, string $uri, array $data = [], array $options = []): Response
|
|
143
|
+
public function authenticatedRequest(string $method, string $uri, string|array $data = [], array $options = []): Response
|
|
116
144
|
{
|
|
117
145
|
if (!$this->identity) {
|
|
118
146
|
throw new \Exception('Solid Identity required to make an authenticated request.');
|
|
@@ -120,13 +148,81 @@ class SolidClient
|
|
|
120
148
|
|
|
121
149
|
$url = $this->createRequestUrl($uri);
|
|
122
150
|
$accessToken = $this->identity->getAccessToken();
|
|
151
|
+
|
|
152
|
+
// Debug: Log access token details
|
|
123
153
|
if ($accessToken) {
|
|
124
|
-
|
|
154
|
+
try {
|
|
155
|
+
$tokenParts = explode('.', $accessToken);
|
|
156
|
+
if (count($tokenParts) === 3) {
|
|
157
|
+
$payload = json_decode(base64_decode(strtr($tokenParts[1], '-_', '+/')), true);
|
|
158
|
+
Log::debug('[ACCESS TOKEN PAYLOAD]', [
|
|
159
|
+
'webid' => $payload['webid'] ?? null,
|
|
160
|
+
'sub' => $payload['sub'] ?? null,
|
|
161
|
+
'client_id' => $payload['client_id'] ?? null,
|
|
162
|
+
'scope' => $payload['scope'] ?? null,
|
|
163
|
+
'iat' => $payload['iat'] ?? null,
|
|
164
|
+
'exp' => $payload['exp'] ?? null,
|
|
165
|
+
'cnf_jkt' => $payload['cnf']['jkt'] ?? null,
|
|
166
|
+
]);
|
|
167
|
+
}
|
|
168
|
+
} catch (\Throwable $e) {
|
|
169
|
+
Log::warning('[ACCESS TOKEN DECODE FAILED]', ['error' => $e->getMessage()]);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
$options['headers'] = isset($options['headers']) && is_array($options['headers']) ? $options['headers'] : [];
|
|
125
173
|
$options['headers']['Authorization'] = 'DPoP ' . $accessToken;
|
|
126
|
-
$options['headers']['DPoP'] =
|
|
174
|
+
$options['headers']['DPoP'] = $this->oidc->createDPoP($method, $url, $accessToken);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// For development: disable SSL verification when using HTTPS
|
|
178
|
+
if ($this->secure && app()->environment('local', 'development')) {
|
|
179
|
+
$options['verify'] = false;
|
|
127
180
|
}
|
|
128
181
|
|
|
129
|
-
|
|
182
|
+
Log::info('[SOLID REQUEST HEADERS]', ['headers' => $options['headers']]);
|
|
183
|
+
|
|
184
|
+
// Handle different data types
|
|
185
|
+
if (is_string($data)) {
|
|
186
|
+
// For string data, send as raw body
|
|
187
|
+
$contentType = $options['headers']['Content-Type'] ?? 'text/plain';
|
|
188
|
+
|
|
189
|
+
Log::info('[SENDING STRING BODY]', [
|
|
190
|
+
'method' => $method,
|
|
191
|
+
'url' => $url,
|
|
192
|
+
'content_type' => $contentType,
|
|
193
|
+
'body_length' => strlen($data),
|
|
194
|
+
'body_preview' => substr($data, 0, 200),
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
$response = Http::withOptions($options)->withBody($data, $contentType)->send($method, $url);
|
|
198
|
+
|
|
199
|
+
// Debug: Log response details
|
|
200
|
+
Log::debug('[SOLID RESPONSE]', [
|
|
201
|
+
'status' => $response->status(),
|
|
202
|
+
'headers' => $response->headers(),
|
|
203
|
+
'body' => $response->body(),
|
|
204
|
+
]);
|
|
205
|
+
|
|
206
|
+
return $response;
|
|
207
|
+
} else {
|
|
208
|
+
// For array data, use the original method
|
|
209
|
+
Log::info('[SENDING ARRAY DATA]', [
|
|
210
|
+
'method' => $method,
|
|
211
|
+
'url' => $url,
|
|
212
|
+
'data' => $data,
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
$response = Http::withOptions($options)->{$method}($url, $data);
|
|
216
|
+
|
|
217
|
+
// Debug: Log response details
|
|
218
|
+
Log::debug('[SOLID RESPONSE]', [
|
|
219
|
+
'status' => $response->status(),
|
|
220
|
+
'headers' => $response->headers(),
|
|
221
|
+
'body' => $response->body(),
|
|
222
|
+
]);
|
|
223
|
+
|
|
224
|
+
return $response;
|
|
225
|
+
}
|
|
130
226
|
}
|
|
131
227
|
|
|
132
228
|
/**
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\Solid\Http\Controllers;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Controllers\Controller as BaseController;
|
|
6
|
+
use Fleetbase\Solid\Models\SolidIdentity;
|
|
7
|
+
use Fleetbase\Solid\Services\PodService;
|
|
8
|
+
use Fleetbase\Solid\Services\ResourceSyncService;
|
|
9
|
+
use Illuminate\Http\Request;
|
|
10
|
+
use Illuminate\Support\Facades\Log;
|
|
11
|
+
|
|
12
|
+
class DataController extends BaseController
|
|
13
|
+
{
|
|
14
|
+
protected PodService $podService;
|
|
15
|
+
protected ResourceSyncService $resourceSyncService;
|
|
16
|
+
|
|
17
|
+
public function __construct(PodService $podService, ResourceSyncService $resourceSyncService)
|
|
18
|
+
{
|
|
19
|
+
$this->podService = $podService;
|
|
20
|
+
$this->resourceSyncService = $resourceSyncService;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the user's pod data (root level folders and files).
|
|
25
|
+
*/
|
|
26
|
+
public function index(Request $request)
|
|
27
|
+
{
|
|
28
|
+
try {
|
|
29
|
+
$identity = SolidIdentity::current();
|
|
30
|
+
|
|
31
|
+
if (!$identity || !$identity->getAccessToken()) {
|
|
32
|
+
return response()->json(['error' => 'Not authenticated'], 401);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Get the user's primary pod URL from their WebID
|
|
36
|
+
$profile = $this->podService->getProfileData($identity);
|
|
37
|
+
$webId = $profile['webid'];
|
|
38
|
+
$podUrl = $this->podService->getPodUrlFromWebId($webId);
|
|
39
|
+
|
|
40
|
+
Log::info('[DATA INDEX]', [
|
|
41
|
+
'webid' => $webId,
|
|
42
|
+
'pod_url' => $podUrl,
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
// Get root level contents of the pod
|
|
46
|
+
$contents = $this->podService->getPodContents($identity, $podUrl);
|
|
47
|
+
|
|
48
|
+
return response()->json([
|
|
49
|
+
'pod_url' => $podUrl,
|
|
50
|
+
'contents' => $contents,
|
|
51
|
+
]);
|
|
52
|
+
} catch (\Throwable $e) {
|
|
53
|
+
Log::error('[DATA INDEX ERROR]', [
|
|
54
|
+
'error' => $e->getMessage(),
|
|
55
|
+
'trace' => $e->getTraceAsString(),
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
return response()->json([
|
|
59
|
+
'error' => $e->getMessage(),
|
|
60
|
+
], 500);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get folder contents by slug.
|
|
66
|
+
*/
|
|
67
|
+
public function showFolder(Request $request, string $slug)
|
|
68
|
+
{
|
|
69
|
+
try {
|
|
70
|
+
$identity = SolidIdentity::current();
|
|
71
|
+
|
|
72
|
+
if (!$identity || !$identity->getAccessToken()) {
|
|
73
|
+
return response()->json(['error' => 'Not authenticated'], 401);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
$profile = $this->podService->getProfileData($identity);
|
|
77
|
+
$webId = $profile['webid'];
|
|
78
|
+
$podUrl = $this->podService->getPodUrlFromWebId($webId);
|
|
79
|
+
$folderUrl = rtrim($podUrl, '/') . '/' . ltrim($slug, '/');
|
|
80
|
+
|
|
81
|
+
Log::info('[FOLDER SHOW]', [
|
|
82
|
+
'slug' => $slug,
|
|
83
|
+
'folder_url' => $folderUrl,
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
$contents = $this->podService->getPodContents($identity, $folderUrl);
|
|
87
|
+
|
|
88
|
+
return response()->json([
|
|
89
|
+
'folder_url' => $folderUrl,
|
|
90
|
+
'slug' => $slug,
|
|
91
|
+
'contents' => $contents,
|
|
92
|
+
]);
|
|
93
|
+
} catch (\Throwable $e) {
|
|
94
|
+
Log::error('[FOLDER SHOW ERROR]', [
|
|
95
|
+
'slug' => $slug,
|
|
96
|
+
'error' => $e->getMessage(),
|
|
97
|
+
]);
|
|
98
|
+
|
|
99
|
+
return response()->json([
|
|
100
|
+
'error' => $e->getMessage(),
|
|
101
|
+
], 500);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Create a new folder in the pod.
|
|
107
|
+
*/
|
|
108
|
+
public function createFolder(Request $request)
|
|
109
|
+
{
|
|
110
|
+
try {
|
|
111
|
+
$identity = SolidIdentity::current();
|
|
112
|
+
|
|
113
|
+
if (!$identity || !$identity->getAccessToken()) {
|
|
114
|
+
return response()->json(['error' => 'Not authenticated'], 401);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
$request->validate([
|
|
118
|
+
'name' => 'required|string|max:255',
|
|
119
|
+
'path' => 'nullable|string',
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
$folderName = $request->input('name');
|
|
123
|
+
$path = $request->input('path', '');
|
|
124
|
+
|
|
125
|
+
$profile = $this->podService->getProfileData($identity);
|
|
126
|
+
$webId = $profile['webid'];
|
|
127
|
+
$podUrl = $this->podService->getPodUrlFromWebId($webId);
|
|
128
|
+
|
|
129
|
+
// Build parent URL (where to create the folder)
|
|
130
|
+
$parentUrl = rtrim($podUrl, '/') . '/';
|
|
131
|
+
if (!empty($path)) {
|
|
132
|
+
$parentUrl .= trim($path, '/') . '/';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
Log::info('[FOLDER CREATE]', [
|
|
136
|
+
'name' => $folderName,
|
|
137
|
+
'path' => $path,
|
|
138
|
+
'parent_url' => $parentUrl,
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
// Use POST with Slug header (Solid Protocol standard)
|
|
142
|
+
$result = $this->podService->createFolder($identity, $parentUrl, $folderName);
|
|
143
|
+
|
|
144
|
+
return response()->json([
|
|
145
|
+
'success' => $result,
|
|
146
|
+
'folder_url' => $parentUrl . $folderName . '/',
|
|
147
|
+
'message' => "Folder '{$folderName}' created successfully",
|
|
148
|
+
]);
|
|
149
|
+
} catch (\Throwable $e) {
|
|
150
|
+
Log::error('[FOLDER CREATE ERROR]', [
|
|
151
|
+
'error' => $e->getMessage(),
|
|
152
|
+
'trace' => $e->getTraceAsString(),
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
return response()->json([
|
|
156
|
+
'success' => false,
|
|
157
|
+
'error' => $e->getMessage(),
|
|
158
|
+
], 500);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Delete a folder or file.
|
|
164
|
+
*/
|
|
165
|
+
public function deleteItem(Request $request, string $type, string $slug)
|
|
166
|
+
{
|
|
167
|
+
try {
|
|
168
|
+
$identity = SolidIdentity::current();
|
|
169
|
+
|
|
170
|
+
if (!$identity || !$identity->getAccessToken()) {
|
|
171
|
+
return response()->json(['error' => 'Not authenticated'], 401);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
$profile = $this->podService->getProfileData($identity);
|
|
175
|
+
$webId = $profile['webid'];
|
|
176
|
+
$podUrl = $this->podService->getPodUrlFromWebId($webId);
|
|
177
|
+
$itemUrl = rtrim($podUrl, '/') . '/' . ltrim($slug, '/');
|
|
178
|
+
|
|
179
|
+
// Add trailing slash for folders
|
|
180
|
+
if ($type === 'folder') {
|
|
181
|
+
$itemUrl = rtrim($itemUrl, '/') . '/';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
Log::info('[ITEM DELETE]', [
|
|
185
|
+
'type' => $type,
|
|
186
|
+
'slug' => $slug,
|
|
187
|
+
'item_url' => $itemUrl,
|
|
188
|
+
]);
|
|
189
|
+
|
|
190
|
+
$result = $this->podService->deleteResource($identity, $itemUrl);
|
|
191
|
+
|
|
192
|
+
return response()->json([
|
|
193
|
+
'success' => $result,
|
|
194
|
+
'message' => $result ? ucfirst($type) . ' deleted successfully' : 'Failed to delete ' . $type,
|
|
195
|
+
]);
|
|
196
|
+
} catch (\Throwable $e) {
|
|
197
|
+
Log::error('[ITEM DELETE ERROR]', [
|
|
198
|
+
'type' => $type,
|
|
199
|
+
'slug' => $slug,
|
|
200
|
+
'error' => $e->getMessage(),
|
|
201
|
+
]);
|
|
202
|
+
|
|
203
|
+
return response()->json([
|
|
204
|
+
'success' => false,
|
|
205
|
+
'error' => $e->getMessage(),
|
|
206
|
+
], 500);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Import Fleetops resources into the user's pod.
|
|
212
|
+
*/
|
|
213
|
+
public function importResources(Request $request)
|
|
214
|
+
{
|
|
215
|
+
try {
|
|
216
|
+
$identity = SolidIdentity::current();
|
|
217
|
+
|
|
218
|
+
if (!$identity || !$identity->getAccessToken()) {
|
|
219
|
+
return response()->json(['error' => 'Not authenticated'], 401);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
$request->validate([
|
|
223
|
+
'resource_types' => 'required|array',
|
|
224
|
+
'resource_types.*' => 'in:vehicles,drivers,contacts,orders',
|
|
225
|
+
]);
|
|
226
|
+
|
|
227
|
+
$resourceTypes = $request->input('resource_types');
|
|
228
|
+
|
|
229
|
+
// Use the authenticated user's pod (from their WebID)
|
|
230
|
+
$profile = $this->podService->getProfileData($identity);
|
|
231
|
+
$webId = $profile['webid'];
|
|
232
|
+
$podUrl = $this->podService->getPodUrlFromWebId($webId);
|
|
233
|
+
|
|
234
|
+
Log::info('[IMPORTING RESOURCES]', [
|
|
235
|
+
'pod_url' => $podUrl,
|
|
236
|
+
'webid' => $webId,
|
|
237
|
+
'resource_types' => $resourceTypes,
|
|
238
|
+
]);
|
|
239
|
+
|
|
240
|
+
$result = $this->resourceSyncService->importResources($identity, $podUrl, $resourceTypes);
|
|
241
|
+
|
|
242
|
+
return response()->json([
|
|
243
|
+
'success' => true,
|
|
244
|
+
'imported' => $result['imported'],
|
|
245
|
+
'imported_count' => $result['total_count'],
|
|
246
|
+
'errors' => $result['errors'],
|
|
247
|
+
'message' => "Successfully imported {$result['total_count']} resources",
|
|
248
|
+
]);
|
|
249
|
+
} catch (\Throwable $e) {
|
|
250
|
+
Log::error('[IMPORT RESOURCES ERROR]', [
|
|
251
|
+
'error' => $e->getMessage(),
|
|
252
|
+
'trace' => $e->getTraceAsString(),
|
|
253
|
+
]);
|
|
254
|
+
|
|
255
|
+
return response()->json([
|
|
256
|
+
'success' => false,
|
|
257
|
+
'error' => $e->getMessage(),
|
|
258
|
+
], 500);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -7,26 +7,60 @@ use Fleetbase\Solid\Client\SolidClient;
|
|
|
7
7
|
use Fleetbase\Solid\Models\SolidIdentity;
|
|
8
8
|
use Fleetbase\Support\Utils;
|
|
9
9
|
use Illuminate\Http\Request;
|
|
10
|
+
use Illuminate\Support\Facades\Log;
|
|
10
11
|
|
|
11
12
|
class OIDCController extends BaseController
|
|
12
13
|
{
|
|
13
14
|
public function completeRegistration(string $identifier, Request $request)
|
|
14
15
|
{
|
|
15
|
-
|
|
16
|
+
Log::info('[OIDC COMPLETE REGISTRATION]', [
|
|
17
|
+
'identifier' => $identifier,
|
|
18
|
+
'request' => $request->all(),
|
|
19
|
+
'has_code' => $request->filled('code'),
|
|
20
|
+
'has_state' => $request->filled('state'),
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
if ($request->filled('code') && $identifier) {
|
|
16
24
|
try {
|
|
17
25
|
$identity = SolidIdentity::where('identifier', $identifier)->first();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
$
|
|
21
|
-
|
|
26
|
+
|
|
27
|
+
if (!$identity) {
|
|
28
|
+
throw new \Exception('Identity not found for identifier: ' . $identifier);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Log::info('[OIDC IDENTITY FOUND]', ['identity_id' => $identity->id]);
|
|
32
|
+
|
|
33
|
+
$solid = SolidClient::create(['identity' => $identity, 'restore' => true]);
|
|
34
|
+
|
|
35
|
+
// Get the authorization code
|
|
36
|
+
$code = $request->input('code');
|
|
37
|
+
|
|
38
|
+
// CRITICAL: Use requestTokens() instead of authenticate()
|
|
39
|
+
$tokenResponse = $solid->oidc->exchangeCodeForTokens($code);
|
|
40
|
+
|
|
41
|
+
if (isset($tokenResponse->error)) {
|
|
42
|
+
throw new \Exception($tokenResponse->error_description ?? $tokenResponse->error);
|
|
22
43
|
}
|
|
44
|
+
|
|
45
|
+
Log::info('[OIDC TOKEN EXCHANGE SUCCESS]', ['has_access_token' => isset($tokenResponse->access_token)]);
|
|
46
|
+
|
|
47
|
+
// Save the token response
|
|
48
|
+
$identity->update(['token_response' => (array) $tokenResponse]);
|
|
49
|
+
|
|
50
|
+
// Redirect to success page
|
|
51
|
+
return redirect(Utils::consoleUrl('solid-protocol', ['success' => 'authenticated']));
|
|
23
52
|
} catch (\Throwable $e) {
|
|
53
|
+
Log::error('[OIDC ERROR]', [
|
|
54
|
+
'error' => $e->getMessage(),
|
|
55
|
+
'trace' => $e->getTraceAsString(),
|
|
56
|
+
]);
|
|
57
|
+
|
|
24
58
|
return redirect(Utils::consoleUrl('solid-protocol', ['error' => $e->getMessage()]));
|
|
25
59
|
}
|
|
26
|
-
|
|
27
|
-
return redirect(Utils::consoleUrl('solid-protocol', $request->all()));
|
|
28
60
|
}
|
|
29
61
|
|
|
30
|
-
|
|
62
|
+
Log::warning('[OIDC MISSING PARAMS]', ['has_code' => $request->filled('code'), 'identifier' => $identifier]);
|
|
63
|
+
|
|
64
|
+
return redirect(Utils::consoleUrl('solid-protocol', ['error' => 'Missing authorization code or identifier']));
|
|
31
65
|
}
|
|
32
66
|
}
|