@fleetbase/registry-bridge-engine 0.0.2 → 0.0.3

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.
@@ -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: 'Extensions Awaiting Review',
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: 'Extensions Pending Publish',
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
- {{#unless this.hasStripeConnectAccount}}
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
- {{/unless}}
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>
@@ -0,0 +1 @@
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.2",
3
+ "version": "0.0.3",
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.28",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Registry Bridge",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Internal Bridge between Fleetbase API and Extensions Registry",
5
5
  "repository": "https://github.com/fleetbase/registry-bridge",
6
6
  "license": "AGPL-3.0-or-later",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/registry-bridge-engine",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
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.18",
44
- "@fortawesome/ember-fontawesome": "^0.4.1",
45
- "@fortawesome/fontawesome-svg-core": "^6.5.2",
46
- "@fortawesome/free-solid-svg-icons": "^6.5.2",
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
  }
@@ -3,7 +3,7 @@
3
3
  namespace Fleetbase\RegistryBridge\Http\Filter;
4
4
 
5
5
  use Fleetbase\Http\Filter\Filter;
6
- use Fleetbase\Support\Utils;
6
+ use Fleetbase\RegistryBridge\Support\Utils;
7
7
  use Illuminate\Support\Str;
8
8
 
9
9
  class RegistryExtensionFilter extends Filter
@@ -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 = SupportUtils::calculatePercentage(config('registry-bridge.facilitator_fee', 10), $totalAmount);
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' => SupportUtils::consoleUrl($returnUri) . '?extension_id=' . $this->uuid . '&checkout_session_id={CHECKOUT_SESSION_ID}',
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
- static::bootRegistryAuth();
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
- $homeDirectory = rtrim(getenv('HOME'), '/');
100
- $authPath = $homeDirectory . '/.npmrc';
101
- $authString = '//' . str_replace(['http://', 'https://'], '', rtrim(config('registry-bridge.registry.host'), '/')) . '/:_authToken="' . config('registry-bridge.registry.token') . '"' . PHP_EOL;
102
- if (!file_exists($authPath) || $reset === true) {
103
- file_put_contents($authPath, $authString);
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
- $consolePath = rtrim(config('fleetbase.console.path'), '/');
107
- $registryPath = $consolePath . '/.npmrc';
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
  }
@@ -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) {