@fleetbase/registry-bridge-engine 0.0.2 → 0.0.4
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/addon/components/registry-admin-config.hbs +16 -0
- package/addon/components/registry-admin-config.js +36 -0
- package/addon/controllers/developers/payments/index.js +1 -0
- package/addon/engine.js +8 -2
- package/addon/templates/developers/payments/index.hbs +14 -13
- package/addon/templates/installed.hbs +3 -3
- package/addon/templates/purchased.hbs +5 -23
- package/app/components/{progress-bar.js → registry-admin-config.js} +1 -1
- package/composer.json +2 -2
- package/extension.json +1 -1
- package/package.json +5 -5
- package/server/src/Http/Controllers/Internal/v1/RegistryAuthController.php +46 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryExtensionBundleController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/RegistryExtensionController.php +59 -1
- package/server/src/Http/Filter/RegistryExtensionFilter.php +1 -1
- package/server/src/Models/RegistryExtension.php +2 -3
- package/server/src/Models/RegistryExtensionBundle.php +1 -1
- package/server/src/Providers/RegistryBridgeServiceProvider.php +16 -30
- package/server/src/Support/Utils.php +136 -1
- package/server/src/routes.php +3 -0
- package/addon/components/progress-bar.hbs +0 -12
- package/addon/components/progress-bar.js +0 -8
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<ContentPanel @title="Registry Configuration" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
|
2
|
+
<InputGroup @name="Registry Host" @value={{this.registryHost}} disabled={{or this.getConfigValues.isRunning this.saveConfigValues.isRunning}} />
|
|
3
|
+
<InputGroup @name="Registry Token" @value={{this.registryToken}} disabled={{or this.getConfigValues.isRunning this.saveConfigValues.isRunning}} />
|
|
4
|
+
</ContentPanel>
|
|
5
|
+
<EmberWormhole @to="next-view-section-subheader-actions">
|
|
6
|
+
<Button
|
|
7
|
+
@type="primary"
|
|
8
|
+
@size="sm"
|
|
9
|
+
@icon="save"
|
|
10
|
+
@text="Save Changes"
|
|
11
|
+
@onClick={{perform this.saveConfigValues}}
|
|
12
|
+
@disabled={{or this.getConfigValues.isRunning this.saveConfigValues.isRunning}}
|
|
13
|
+
@isLoading={{this.saveConfigValues.isRunning}}
|
|
14
|
+
/>
|
|
15
|
+
</EmberWormhole>
|
|
16
|
+
<Spacer @height="400px" />
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
import { tracked } from '@glimmer/tracking';
|
|
4
|
+
import { task } from 'ember-concurrency';
|
|
5
|
+
|
|
6
|
+
export default class RegistryAdminConfigComponent extends Component {
|
|
7
|
+
@service fetch;
|
|
8
|
+
@service notifications;
|
|
9
|
+
@tracked registryHost;
|
|
10
|
+
@tracked registryToken;
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
this.getConfigValues.perform();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@task *getConfigValues() {
|
|
18
|
+
try {
|
|
19
|
+
const { host, token } = yield this.fetch.get('registry-extensions/config', {}, { namespace: '~registry/v1' });
|
|
20
|
+
this.registryHost = host;
|
|
21
|
+
this.registryToken = token;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
this.notifications.serverError(error);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@task *saveConfigValues() {
|
|
28
|
+
try {
|
|
29
|
+
const { host, token } = yield this.fetch.post('registry-extensions/config', { host: this.registryHost, token: this.registryToken }, { namespace: '~registry/v1' });
|
|
30
|
+
this.registryHost = host;
|
|
31
|
+
this.registryToken = token;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
this.notifications.serverError(error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
package/addon/engine.js
CHANGED
|
@@ -3,6 +3,7 @@ import loadInitializers from 'ember-load-initializers';
|
|
|
3
3
|
import Resolver from 'ember-resolver';
|
|
4
4
|
import config from './config/environment';
|
|
5
5
|
import services from '@fleetbase/ember-core/exports/services';
|
|
6
|
+
import RegistryAdminConfigComponent from './components/registry-admin-config';
|
|
6
7
|
import ExtensionReviewerControlComponent from './components/extension-reviewer-control';
|
|
7
8
|
import ExtensionPendingPublishViewerComponent from './components/extension-pending-publish-viewer';
|
|
8
9
|
|
|
@@ -24,12 +25,17 @@ export default class RegistryBridgeEngine extends Engine {
|
|
|
24
25
|
'Extensions Registry',
|
|
25
26
|
[
|
|
26
27
|
{
|
|
27
|
-
title: '
|
|
28
|
+
title: 'Registry Config',
|
|
29
|
+
icon: 'gear',
|
|
30
|
+
component: RegistryAdminConfigComponent,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
title: 'Awaiting Review',
|
|
28
34
|
icon: 'gavel',
|
|
29
35
|
component: ExtensionReviewerControlComponent,
|
|
30
36
|
},
|
|
31
37
|
{
|
|
32
|
-
title: '
|
|
38
|
+
title: 'Pending Publish',
|
|
33
39
|
icon: 'rocket',
|
|
34
40
|
component: ExtensionPendingPublishViewerComponent,
|
|
35
41
|
},
|
|
@@ -6,7 +6,19 @@
|
|
|
6
6
|
</Layout::Section::Header>
|
|
7
7
|
|
|
8
8
|
<Layout::Section::Body class="overflow-y-scroll h-full">
|
|
9
|
-
{{#
|
|
9
|
+
{{#if this.hasStripeConnectAccount}}
|
|
10
|
+
<Table
|
|
11
|
+
@rows={{@model.data}}
|
|
12
|
+
@columns={{this.columns}}
|
|
13
|
+
@selectable={{false}}
|
|
14
|
+
@canSelectAll={{false}}
|
|
15
|
+
@onSetup={{fn (mut this.table)}}
|
|
16
|
+
@pagination={{true}}
|
|
17
|
+
@paginationMeta={{@model.meta}}
|
|
18
|
+
@page={{this.page}}
|
|
19
|
+
@onPageChange={{fn (mut this.page)}}
|
|
20
|
+
/>
|
|
21
|
+
{{else}}
|
|
10
22
|
<div class="container">
|
|
11
23
|
<div class="max-w-3xl mx-auto mt-4">
|
|
12
24
|
<div class="content">
|
|
@@ -18,16 +30,5 @@
|
|
|
18
30
|
</div>
|
|
19
31
|
</div>
|
|
20
32
|
</div>
|
|
21
|
-
{{/
|
|
22
|
-
<Table
|
|
23
|
-
@rows={{@model.data}}
|
|
24
|
-
@columns={{this.columns}}
|
|
25
|
-
@selectable={{false}}
|
|
26
|
-
@canSelectAll={{false}}
|
|
27
|
-
@onSetup={{fn (mut this.table)}}
|
|
28
|
-
@pagination={{true}}
|
|
29
|
-
@paginationMeta={{@model.meta}}
|
|
30
|
-
@page={{this.page}}
|
|
31
|
-
@onPageChange={{fn (mut this.page)}}
|
|
32
|
-
/>
|
|
33
|
+
{{/if}}
|
|
33
34
|
</Layout::Section::Body>
|
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
<div class="font-semibold text-sm block">{{extension.name}}</div>
|
|
14
14
|
<div class="text-xs">{{n-a extension.description}}</div>
|
|
15
15
|
</div>
|
|
16
|
-
<div class="pt-1 space-y-2">
|
|
16
|
+
<div class="flex flex-col flex-1 pt-1 space-y-2">
|
|
17
17
|
<Button
|
|
18
18
|
@type="default"
|
|
19
19
|
@text={{t "registry-bridge.common.about-extension" extensionName=extension.name}}
|
|
20
20
|
@icon="circle-info"
|
|
21
21
|
@onClick={{fn this.about extension}}
|
|
22
|
-
class="w-full"
|
|
22
|
+
class="w-full btn-block"
|
|
23
23
|
/>
|
|
24
|
-
<Button @type="danger" @text={{t "registry-bridge.common.uninstall"}} @icon="trash" @onClick={{fn this.uninstall extension}} class="w-full" />
|
|
24
|
+
<Button @type="danger" @text={{t "registry-bridge.common.uninstall"}} @icon="trash" @onClick={{fn this.uninstall extension}} class="w-full btn-block" />
|
|
25
25
|
</div>
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
@@ -4,29 +4,11 @@
|
|
|
4
4
|
<div class="m-auto p-8">
|
|
5
5
|
<div class="extension-card-grid-container">
|
|
6
6
|
{{#each @model as |extension|}}
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<div class="flex flex-col">
|
|
13
|
-
<div class="font-semibold text-sm block">{{extension.name}}</div>
|
|
14
|
-
<div class="text-xs">{{n-a extension.description}}</div>
|
|
15
|
-
</div>
|
|
16
|
-
{{#if extension.is_installed}}
|
|
17
|
-
<Badge @status="success" @hideStatusDot={{true}} class="mt-1"><FaIcon @icon="check" class="mr-1" /> Installed</Badge>
|
|
18
|
-
{{/if}}
|
|
19
|
-
<div class="pt-1 space-y-2">
|
|
20
|
-
<Button
|
|
21
|
-
@type="default"
|
|
22
|
-
@text={{t "registry-bridge.common.about-extension" extensionName=extension.name}}
|
|
23
|
-
@icon="circle-info"
|
|
24
|
-
@onClick={{fn this.about extension}}
|
|
25
|
-
class="w-full"
|
|
26
|
-
/>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
7
|
+
<ExtensionCard @extension={{extension}}>
|
|
8
|
+
{{#if extension.is_installed}}
|
|
9
|
+
<Badge @status="success" @hideStatusDot={{true}} class="mt-1"><FaIcon @icon="check" class="mr-1" /> Installed</Badge>
|
|
10
|
+
{{/if}}
|
|
11
|
+
</ExtensionCard>
|
|
30
12
|
{{/each}}
|
|
31
13
|
</div>
|
|
32
14
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from '@fleetbase/registry-bridge-engine/components/
|
|
1
|
+
export { default } from '@fleetbase/registry-bridge-engine/components/registry-admin-config';
|
package/composer.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fleetbase/registry-bridge",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Internal Bridge between Fleetbase API and Extensions Registry",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fleetbase-extension",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"require": {
|
|
22
22
|
"php": "^8.0",
|
|
23
|
-
"fleetbase/core-api": "^1.4.
|
|
23
|
+
"fleetbase/core-api": "^1.4.30",
|
|
24
24
|
"laravel/cashier": "^15.2.1",
|
|
25
25
|
"php-http/guzzle7-adapter": "^1.0",
|
|
26
26
|
"psr/http-factory-implementation": "*",
|
package/extension.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetbase/registry-bridge-engine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Internal Bridge between Fleetbase API and Extensions Registry",
|
|
5
5
|
"fleetbase": {
|
|
6
6
|
"route": "extensions"
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@babel/core": "^7.23.2",
|
|
42
42
|
"@fleetbase/ember-core": "^0.2.13",
|
|
43
|
-
"@fleetbase/ember-ui": "^0.2.
|
|
44
|
-
"@fortawesome/ember-fontawesome": "^0.
|
|
45
|
-
"@fortawesome/fontawesome-svg-core": "
|
|
46
|
-
"@fortawesome/free-solid-svg-icons": "
|
|
43
|
+
"@fleetbase/ember-ui": "^0.2.19",
|
|
44
|
+
"@fortawesome/ember-fontawesome": "^2.0.0",
|
|
45
|
+
"@fortawesome/fontawesome-svg-core": "6.4.0",
|
|
46
|
+
"@fortawesome/free-solid-svg-icons": "6.4.0",
|
|
47
47
|
"@stripe/connect-js": "^3.3.10",
|
|
48
48
|
"ember-auto-import": "^2.6.3",
|
|
49
49
|
"ember-cli-babel": "^8.2.0",
|
|
@@ -17,6 +17,52 @@ use Illuminate\Support\Str;
|
|
|
17
17
|
|
|
18
18
|
class RegistryAuthController extends Controller
|
|
19
19
|
{
|
|
20
|
+
/**
|
|
21
|
+
* Handle Composer authentication and return a list of unauthorized packages.
|
|
22
|
+
*
|
|
23
|
+
* This function authenticates the user based on the provided registry token.
|
|
24
|
+
* If the token is valid, it returns a list of packages that the user is not authorized to access.
|
|
25
|
+
*
|
|
26
|
+
* @param Request $request the incoming HTTP request containing the registry token
|
|
27
|
+
*
|
|
28
|
+
* @return \Illuminate\Http\JsonResponse a JSON response containing the status and a list of unauthorized packages
|
|
29
|
+
*/
|
|
30
|
+
public function composerAuthentication(Request $request)
|
|
31
|
+
{
|
|
32
|
+
$registryToken = $request->input('registryToken');
|
|
33
|
+
if (!$registryToken) {
|
|
34
|
+
return response()->error('No registry token provided for authentication.', 401);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Get registry user via token
|
|
38
|
+
$registryUser = RegistryUser::where('registry_token', $registryToken)->first();
|
|
39
|
+
if (!$registryUser) {
|
|
40
|
+
return response()->error('Invalid registry token provided for authentication.', 401);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Fetch unauthorized extensions
|
|
44
|
+
$unauthorizedExtensions = RegistryExtension::where('payment_required', true)
|
|
45
|
+
->whereDoesntHave('purchases', function ($query) use ($registryUser) {
|
|
46
|
+
$query->where('company_uuid', $registryUser->company_uuid);
|
|
47
|
+
})
|
|
48
|
+
->whereHas('currentBundle')
|
|
49
|
+
->with('currentBundle')
|
|
50
|
+
->get();
|
|
51
|
+
|
|
52
|
+
// Map to unathorized to package names
|
|
53
|
+
$unauthorizedExtensionNames = $unauthorizedExtensions->map(function ($registryExtension) {
|
|
54
|
+
$composerJson = $registryExtension->currentBundle->meta['composer.json'] ?? [];
|
|
55
|
+
|
|
56
|
+
return $composerJson['name'] ?? null;
|
|
57
|
+
})->filter()->values();
|
|
58
|
+
|
|
59
|
+
// Done
|
|
60
|
+
return response()->json([
|
|
61
|
+
'status' => 'ok',
|
|
62
|
+
'unauthorizedPackages' => $unauthorizedExtensionNames,
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
|
|
20
66
|
/**
|
|
21
67
|
* Authenticates a registry user based on provided credentials.
|
|
22
68
|
*
|
|
@@ -8,7 +8,7 @@ use Fleetbase\RegistryBridge\Http\Controllers\RegistryBridgeController;
|
|
|
8
8
|
use Fleetbase\RegistryBridge\Http\Requests\CreateRegistryExtensionBundleRequest;
|
|
9
9
|
use Fleetbase\RegistryBridge\Http\Requests\RegistryExtensionActionRequest;
|
|
10
10
|
use Fleetbase\RegistryBridge\Models\RegistryExtensionBundle;
|
|
11
|
-
use Fleetbase\Support\Utils;
|
|
11
|
+
use Fleetbase\RegistryBridge\Support\Utils;
|
|
12
12
|
use Illuminate\Http\Request;
|
|
13
13
|
use Illuminate\Support\Facades\Storage;
|
|
14
14
|
use Illuminate\Support\Facades\Validator;
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
namespace Fleetbase\RegistryBridge\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
5
|
use Fleetbase\Exceptions\FleetbaseRequestValidationException;
|
|
6
|
+
use Fleetbase\Models\Setting;
|
|
6
7
|
use Fleetbase\RegistryBridge\Http\Controllers\RegistryBridgeController;
|
|
7
8
|
use Fleetbase\RegistryBridge\Http\Requests\CreateRegistryExtensionRequest;
|
|
8
9
|
use Fleetbase\RegistryBridge\Http\Requests\RegistryExtensionActionRequest;
|
|
9
10
|
use Fleetbase\RegistryBridge\Models\RegistryExtension;
|
|
10
|
-
use Fleetbase\Support\Utils;
|
|
11
|
+
use Fleetbase\RegistryBridge\Support\Utils;
|
|
11
12
|
use Illuminate\Http\Request;
|
|
12
13
|
use Illuminate\Support\Facades\Storage;
|
|
13
14
|
use Illuminate\Support\Facades\Validator;
|
|
@@ -254,4 +255,61 @@ class RegistryExtensionController extends RegistryBridgeController
|
|
|
254
255
|
|
|
255
256
|
return response()->error('Failed to download extension bundle');
|
|
256
257
|
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Retrieve the current registry configuration.
|
|
261
|
+
*
|
|
262
|
+
* This method fetches the current registry host and token from the configuration
|
|
263
|
+
* settings or environment variables and returns them in a JSON response.
|
|
264
|
+
*
|
|
265
|
+
* @return \Illuminate\Http\JsonResponse a JSON response containing the registry host and token
|
|
266
|
+
*/
|
|
267
|
+
public function getConfig()
|
|
268
|
+
{
|
|
269
|
+
$registryHost = config('registry-bridge.registry.host', env('REGISTRY_HOST', 'https://registry.fleetbase.io'));
|
|
270
|
+
$registryToken = config('registry-bridge.registry.token', env('REGISTRY_TOKEN'));
|
|
271
|
+
|
|
272
|
+
return response()->json([
|
|
273
|
+
'host' => $registryHost,
|
|
274
|
+
'token' => $registryToken,
|
|
275
|
+
]);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Save the registry configuration.
|
|
280
|
+
*
|
|
281
|
+
* This method updates the registry host and token based on the provided request input.
|
|
282
|
+
* If no input is provided, it uses the current configuration values or environment variables.
|
|
283
|
+
* The updated configuration is then saved in the settings and returned in a JSON response.
|
|
284
|
+
*
|
|
285
|
+
* @param Request $request the incoming HTTP request containing the new host and token
|
|
286
|
+
*
|
|
287
|
+
* @return \Illuminate\Http\JsonResponse a JSON response containing the updated registry host and token
|
|
288
|
+
*/
|
|
289
|
+
public function saveConfig(Request $request)
|
|
290
|
+
{
|
|
291
|
+
$currentRegistryHost = config('registry-bridge.registry.host', env('REGISTRY_HOST', 'https://registry.fleetbase.io'));
|
|
292
|
+
$currentRegistryToken = config('registry-bridge.registry.token', env('REGISTRY_TOKEN'));
|
|
293
|
+
$registryHost = $request->input('host', $currentRegistryHost);
|
|
294
|
+
$registryToken = $request->input('token', $currentRegistryToken);
|
|
295
|
+
|
|
296
|
+
// Save values in settings and config
|
|
297
|
+
if ($registryHost) {
|
|
298
|
+
Setting::configure('registry-bridge.registry.host', $registryHost);
|
|
299
|
+
config(['registry-bridge.registry.host' => $registryHost]);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if ($registryToken) {
|
|
303
|
+
Setting::configure('registry-bridge.registry.token', $registryToken);
|
|
304
|
+
config(['registry-bridge.registry.token' => $registryToken]);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Reboot registry auth
|
|
308
|
+
Utils::bootRegistryAuth(true);
|
|
309
|
+
|
|
310
|
+
return response()->json([
|
|
311
|
+
'host' => $registryHost,
|
|
312
|
+
'token' => $registryToken,
|
|
313
|
+
]);
|
|
314
|
+
}
|
|
257
315
|
}
|
|
@@ -10,7 +10,6 @@ use Fleetbase\Models\File;
|
|
|
10
10
|
use Fleetbase\Models\Model;
|
|
11
11
|
use Fleetbase\Models\User;
|
|
12
12
|
use Fleetbase\RegistryBridge\Support\Utils;
|
|
13
|
-
use Fleetbase\Support\Utils as SupportUtils;
|
|
14
13
|
use Fleetbase\Traits\HasApiModelBehavior;
|
|
15
14
|
use Fleetbase\Traits\HasMetaAttributes;
|
|
16
15
|
use Fleetbase\Traits\HasPublicId;
|
|
@@ -627,7 +626,7 @@ class RegistryExtension extends Model
|
|
|
627
626
|
|
|
628
627
|
// Calculate the fee fleetbase takes for faciliation of extension
|
|
629
628
|
$totalAmount = $price->unit_amount;
|
|
630
|
-
$facilitatorFee =
|
|
629
|
+
$facilitatorFee = Utils::calculatePercentage(config('registry-bridge.facilitator_fee', 10), $totalAmount);
|
|
631
630
|
|
|
632
631
|
// Get the stripe client to create the checkout session
|
|
633
632
|
$stripe = Utils::getStripeClient();
|
|
@@ -642,7 +641,7 @@ class RegistryExtension extends Model
|
|
|
642
641
|
],
|
|
643
642
|
],
|
|
644
643
|
'mode' => 'payment',
|
|
645
|
-
'return_url' =>
|
|
644
|
+
'return_url' => Utils::consoleUrl($returnUri) . '?extension_id=' . $this->uuid . '&checkout_session_id={CHECKOUT_SESSION_ID}',
|
|
646
645
|
'payment_intent_data' => [
|
|
647
646
|
'application_fee_amount' => $facilitatorFee,
|
|
648
647
|
'transfer_data' => [
|
|
@@ -8,8 +8,8 @@ use Fleetbase\Models\File;
|
|
|
8
8
|
use Fleetbase\Models\Model;
|
|
9
9
|
use Fleetbase\Models\User;
|
|
10
10
|
use Fleetbase\RegistryBridge\Exceptions\InstallFailedException;
|
|
11
|
+
use Fleetbase\RegistryBridge\Support\Utils;
|
|
11
12
|
use Fleetbase\Support\SocketCluster\SocketClusterService;
|
|
12
|
-
use Fleetbase\Support\Utils;
|
|
13
13
|
use Fleetbase\Traits\HasApiModelBehavior;
|
|
14
14
|
use Fleetbase\Traits\HasMetaAttributes;
|
|
15
15
|
use Fleetbase\Traits\HasPublicId;
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\RegistryBridge\Providers;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\Models\Setting;
|
|
5
6
|
use Fleetbase\Providers\CoreServiceProvider;
|
|
7
|
+
use Fleetbase\RegistryBridge\Support\Utils;
|
|
6
8
|
|
|
7
9
|
if (!class_exists(CoreServiceProvider::class)) {
|
|
8
10
|
throw new \Exception('Registry Bridge cannot be loaded without `fleetbase/core-api` installed!');
|
|
@@ -70,47 +72,31 @@ class RegistryBridgeServiceProvider extends CoreServiceProvider
|
|
|
70
72
|
*/
|
|
71
73
|
public function boot()
|
|
72
74
|
{
|
|
73
|
-
|
|
75
|
+
Utils::bootRegistryAuth();
|
|
74
76
|
$this->registerCommands();
|
|
75
77
|
$this->registerMiddleware();
|
|
76
78
|
$this->registerExpansionsFrom(__DIR__ . '/../Expansions');
|
|
77
79
|
$this->loadRoutesFrom(__DIR__ . '/../routes.php');
|
|
78
80
|
$this->loadMigrationsFrom(__DIR__ . '/../../migrations');
|
|
79
81
|
$this->mergeConfigFrom(__DIR__ . '/../../config/registry-bridge.php', 'registry-bridge');
|
|
82
|
+
$this->mergeConfigFromSettings();
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
* Initializes and sets up the npm registry authentication configuration.
|
|
84
|
-
*
|
|
85
|
-
* This method constructs the registry authentication string from configuration settings,
|
|
86
|
-
* checks for the existence of an npmrc file in the user's home directory, and creates it
|
|
87
|
-
* with the registry authentication string if it doesn't already exist.
|
|
88
|
-
*
|
|
89
|
-
* The registry configuration and token are pulled from the application's configuration files.
|
|
90
|
-
* It ensures the path to the .npmrc file is correctly formed regardless of trailing slashes
|
|
91
|
-
* in the HOME directory path or the registry host configuration.
|
|
92
|
-
*
|
|
93
|
-
* @param bool $reset - Overwrites existing file, "resetting" the .npmrc
|
|
94
|
-
*
|
|
95
|
-
* @return void
|
|
96
|
-
*/
|
|
97
|
-
public static function bootRegistryAuth(bool $reset = false)
|
|
85
|
+
public function mergeConfigFromSettings()
|
|
98
86
|
{
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
87
|
+
if (Setting::doesntHaveConnection()) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
$registryHost = Setting::getByKey('registry-bridge.registry.host');
|
|
92
|
+
$registryToken = Setting::getByKey('registry-bridge.registry.token');
|
|
93
|
+
|
|
94
|
+
if ($registryHost) {
|
|
95
|
+
config(['registry-bridge.registry.host' => $registryHost->value]);
|
|
104
96
|
}
|
|
105
97
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
$registryString = implode(PHP_EOL, [
|
|
109
|
-
'registry=https://registry.npmjs.org/',
|
|
110
|
-
'@fleetbase:registry=' . rtrim(config('registry-bridge.registry.host'), '/') . '/',
|
|
111
|
-
]) . PHP_EOL;
|
|
112
|
-
if (!file_exists($registryPath) || $reset === true) {
|
|
113
|
-
file_put_contents($registryPath, $registryString);
|
|
98
|
+
if ($registryToken) {
|
|
99
|
+
config(['registry-bridge.registry.token' => $registryToken->value]);
|
|
114
100
|
}
|
|
115
101
|
}
|
|
116
102
|
}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\RegistryBridge\Support;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\Support\Utils as SupportUtils;
|
|
5
6
|
use Stripe\StripeClient;
|
|
6
7
|
|
|
7
|
-
class Utils
|
|
8
|
+
class Utils extends SupportUtils
|
|
8
9
|
{
|
|
9
10
|
/**
|
|
10
11
|
* Get the StripeClient instance.
|
|
@@ -16,4 +17,138 @@ class Utils
|
|
|
16
17
|
...$options,
|
|
17
18
|
]);
|
|
18
19
|
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Set the npm configuration for the console.
|
|
23
|
+
*
|
|
24
|
+
* This function sets the npm configuration in the .npmrc file located in the console path.
|
|
25
|
+
* It sets the registry for npm and the Fleetbase scope registry.
|
|
26
|
+
* If the .npmrc file does not exist or if the reset flag is set to true, it writes the configuration to the file.
|
|
27
|
+
*
|
|
28
|
+
* @param bool $reset whether to reset the configuration if the file already exists
|
|
29
|
+
*
|
|
30
|
+
* @return bool true if the configuration was set, false otherwise
|
|
31
|
+
*/
|
|
32
|
+
public static function setConsoleNpmrcConfig(bool $reset = false): bool
|
|
33
|
+
{
|
|
34
|
+
$npmrcPath = static::consolePath('.npmrc');
|
|
35
|
+
$registryHost = config('registry-bridge.registry.host', env('REGISTRY_HOST', 'https://registry.fleetbase.io'));
|
|
36
|
+
$config = implode(PHP_EOL, [
|
|
37
|
+
'registry=https://registry.npmjs.org/',
|
|
38
|
+
'@fleetbase:registry=' . rtrim($registryHost, '/') . '/',
|
|
39
|
+
]) . PHP_EOL;
|
|
40
|
+
|
|
41
|
+
if (!file_exists($npmrcPath) || $reset === true) {
|
|
42
|
+
file_put_contents($npmrcPath, $config, LOCK_EX);
|
|
43
|
+
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Set the global npm authentication token.
|
|
52
|
+
*
|
|
53
|
+
* This function sets the authentication token in the global .npmrc file located in the user's home directory.
|
|
54
|
+
* If the .npmrc file does not exist or if the reset flag is set to true, it writes the authentication token to the file.
|
|
55
|
+
*
|
|
56
|
+
* @param bool $reset whether to reset the configuration if the file already exists
|
|
57
|
+
*
|
|
58
|
+
* @return bool true if the authentication token was set, false otherwise
|
|
59
|
+
*/
|
|
60
|
+
public static function setGlobalNpmrcAuthKey(bool $reset = false): bool
|
|
61
|
+
{
|
|
62
|
+
$homePath = rtrim(getenv('HOME'), DIRECTORY_SEPARATOR);
|
|
63
|
+
$npmrcPath = $homePath . DIRECTORY_SEPARATOR . '.npmrc';
|
|
64
|
+
$registryHost = config('registry-bridge.registry.host', env('REGISTRY_HOST', 'https://registry.fleetbase.io'));
|
|
65
|
+
$registryToken = config('registry-bridge.registry.token', env('REGISTRY_TOKEN'));
|
|
66
|
+
$authString = '//' . str_replace(['http://', 'https://'], '', rtrim($registryHost, '/')) . '/:_authToken="' . $registryToken . '"' . PHP_EOL;
|
|
67
|
+
|
|
68
|
+
if (!file_exists($npmrcPath) || $reset === true) {
|
|
69
|
+
file_put_contents($npmrcPath, $authString, LOCK_EX);
|
|
70
|
+
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Set the Composer authentication configuration.
|
|
79
|
+
*
|
|
80
|
+
* This function sets or updates the auth.json file with the registry token for authentication.
|
|
81
|
+
* It ensures that no bearer tokens with null or empty values are set.
|
|
82
|
+
*
|
|
83
|
+
* @return bool true if the operation was successful, otherwise false
|
|
84
|
+
*
|
|
85
|
+
* @throws \RuntimeException if there is a JSON encoding/decoding error
|
|
86
|
+
*/
|
|
87
|
+
public static function setComposerAuthConfig(): bool
|
|
88
|
+
{
|
|
89
|
+
$composerAuthPath = base_path('auth.json');
|
|
90
|
+
$registryHost = static::getDomainFromUrl(config('registry-bridge.registry.host', env('REGISTRY_HOST', 'https://registry.fleetbase.io')), true);
|
|
91
|
+
$registryToken = config('registry-bridge.registry.token', env('REGISTRY_TOKEN'));
|
|
92
|
+
|
|
93
|
+
// Ensure the registry token is not null or empty
|
|
94
|
+
if (empty($registryToken)) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
$newBearerConfig = [
|
|
99
|
+
'bearer' => [
|
|
100
|
+
$registryHost => $registryToken,
|
|
101
|
+
],
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
$currentConfig = [];
|
|
105
|
+
|
|
106
|
+
if (file_exists($composerAuthPath)) {
|
|
107
|
+
$jsonContent = file_get_contents($composerAuthPath);
|
|
108
|
+
$currentConfig = json_decode($jsonContent, true);
|
|
109
|
+
if ($currentConfig === null && json_last_error() !== JSON_ERROR_NONE) {
|
|
110
|
+
throw new \RuntimeException('Failed to decode JSON: ' . json_last_error_msg());
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Merge existing config with the new bearer config
|
|
114
|
+
if (isset($currentConfig['bearer'])) {
|
|
115
|
+
$currentConfig['bearer'] = array_merge($currentConfig['bearer'], $newBearerConfig['bearer']);
|
|
116
|
+
} else {
|
|
117
|
+
$currentConfig['bearer'] = $newBearerConfig['bearer'];
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
$currentConfig = $newBearerConfig;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
$jsonContent = json_encode($currentConfig, JSON_PRETTY_PRINT);
|
|
124
|
+
if ($jsonContent === false) {
|
|
125
|
+
throw new \RuntimeException('Failed to encode JSON: ' . json_last_error_msg());
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
file_put_contents($composerAuthPath, $jsonContent, LOCK_EX);
|
|
129
|
+
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Initializes and sets up the npm registry authentication configuration.
|
|
135
|
+
*
|
|
136
|
+
* This method constructs the registry authentication string from configuration settings,
|
|
137
|
+
* checks for the existence of an npmrc file in the user's home directory, and creates it
|
|
138
|
+
* with the registry authentication string if it doesn't already exist.
|
|
139
|
+
*
|
|
140
|
+
* The registry configuration and token are pulled from the application's configuration files.
|
|
141
|
+
* It ensures the path to the .npmrc file is correctly formed regardless of trailing slashes
|
|
142
|
+
* in the HOME directory path or the registry host configuration.
|
|
143
|
+
*
|
|
144
|
+
* @param bool $reset - Overwrites existing file, "resetting" the .npmrc
|
|
145
|
+
*
|
|
146
|
+
* @return void
|
|
147
|
+
*/
|
|
148
|
+
public static function bootRegistryAuth(bool $reset = false)
|
|
149
|
+
{
|
|
150
|
+
Utils::setConsoleNpmrcConfig($reset);
|
|
151
|
+
Utils::setGlobalNpmrcAuthKey($reset);
|
|
152
|
+
Utils::setComposerAuthConfig();
|
|
153
|
+
}
|
|
19
154
|
}
|
package/server/src/routes.php
CHANGED
|
@@ -26,6 +26,7 @@ Route::prefix(config('internals.api.routing.prefix', '~registry'))->middleware([
|
|
|
26
26
|
$router->post('registry-tokens', 'RegistryAuthController@createRegistryUser');
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
$router->post('composer-auth', 'RegistryAuthController@composerAuthentication')->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
|
|
29
30
|
$router->post('authenticate', 'RegistryAuthController@authenticate')->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
|
|
30
31
|
$router->post('add-user', 'RegistryAuthController@addUser')->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
|
|
31
32
|
$router->post('check-access', 'RegistryAuthController@checkAccess')->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
|
|
@@ -58,6 +59,8 @@ Route::prefix(config('internals.api.routing.prefix', '~registry'))->middleware([
|
|
|
58
59
|
$router->get('analytics', $controller('analytics'));
|
|
59
60
|
$router->get('installed', $controller('installed'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
|
|
60
61
|
$router->get('purchased', $controller('purchased'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
|
|
62
|
+
$router->get('config', $controller('getConfig'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
|
|
63
|
+
$router->post('config', $controller('saveConfig'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
|
|
61
64
|
});
|
|
62
65
|
|
|
63
66
|
$router->fleetbaseRoutes('registry-extension-bundles', function ($router, $controller) {
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<div>
|
|
2
|
-
<div class="mb-2 flex justify-between items-center">
|
|
3
|
-
<h3 class="text-sm font-semibold text-gray-800 dark:text-white">{{@title}}</h3>
|
|
4
|
-
<span class="text-sm text-gray-800 dark:text-white">{{@percent}}%</span>
|
|
5
|
-
</div>
|
|
6
|
-
<div class="flex w-full h-2 bg-gray-200 rounded-full overflow-hidden dark:bg-neutral-700" role="progressbar" aria-valuenow={{@percent}} aria-valuemin="0" aria-valuemax="100">
|
|
7
|
-
<div
|
|
8
|
-
class="flex flex-col justify-center rounded-full overflow-hidden bg-blue-600 text-xs text-white text-center whitespace-nowrap transition duration-500 dark:bg-blue-500"
|
|
9
|
-
{{did-update this.setProgress @percent}}
|
|
10
|
-
></div>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|