+
\ No newline at end of file
diff --git a/app/components/modals/create-registry-credentials.js b/app/components/modals/create-registry-credentials.js
new file mode 100644
index 0000000..2183b2a
--- /dev/null
+++ b/app/components/modals/create-registry-credentials.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/registry-bridge-engine/components/modals/create-registry-credentials';
diff --git a/app/controllers/developers/credentials.js b/app/controllers/developers/credentials.js
new file mode 100644
index 0000000..270c673
--- /dev/null
+++ b/app/controllers/developers/credentials.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/registry-bridge-engine/controllers/developers/credentials';
diff --git a/composer.json b/composer.json
index 6df0650..2f0c777 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "fleetbase/registry-bridge",
- "version": "0.0.1",
+ "version": "0.0.2",
"description": "Internal Bridge between Fleetbase API and Extensions Registry",
"keywords": [
"fleetbase-extension",
diff --git a/extension.json b/extension.json
index 1d596bd..1d89d77 100644
--- a/extension.json
+++ b/extension.json
@@ -1,6 +1,6 @@
{
"name": "Registry Bridge",
- "version": "0.0.1",
+ "version": "0.0.2",
"description": "Internal Bridge between Fleetbase API and Extensions Registry",
"repository": "https://github.com/fleetbase/registry-bridge",
"license": "AGPL-3.0-or-later",
diff --git a/package.json b/package.json
index ba93c71..73fedaf 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@fleetbase/registry-bridge-engine",
- "version": "0.0.1",
+ "version": "0.0.2",
"description": "Internal Bridge between Fleetbase API and Extensions Registry",
"fleetbase": {
"route": "extensions"
diff --git a/server/config/registry-bridge.php b/server/config/registry-bridge.php
index 4dfee6e..8609f33 100644
--- a/server/config/registry-bridge.php
+++ b/server/config/registry-bridge.php
@@ -26,7 +26,8 @@
'webhook_secret' => env('STRIPE_WEBHOOK_SECRET'),
],
'extensions' => [
- 'preinstalled' => Utils::castBoolean(env('REGISTRY_PREINSTALLED_EXTENSIONS', false))
+ 'preinstalled' => Utils::castBoolean(env('REGISTRY_PREINSTALLED_EXTENSIONS', false)),
+ 'protected_prefixes' => explode(',', env('REGISTRY_PROTECTED_PREFIXES', '@fleetbase,fleetbase,@flb,@fleetbase-extension,@flb-extension'))
],
'facilitator_fee' => env('REGISTRY_FACILITATOR_FEE', 10)
];
diff --git a/server/migrations/2024_07_18_151000_add_auth_token_column_to_registry_users_table.php b/server/migrations/2024_07_18_151000_add_auth_token_column_to_registry_users_table.php
new file mode 100644
index 0000000..c6522f0
--- /dev/null
+++ b/server/migrations/2024_07_18_151000_add_auth_token_column_to_registry_users_table.php
@@ -0,0 +1,28 @@
+string('registry_token')->nullable()->after('token');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('registry_users', function (Blueprint $table) {
+ $table->dropColumn('registry_token');
+ });
+ }
+};
diff --git a/server/src/Http/Controllers/Internal/v1/RegistryAuthController.php b/server/src/Http/Controllers/Internal/v1/RegistryAuthController.php
index 7e9a4cc..b4c4cee 100644
--- a/server/src/Http/Controllers/Internal/v1/RegistryAuthController.php
+++ b/server/src/Http/Controllers/Internal/v1/RegistryAuthController.php
@@ -12,14 +12,12 @@
use Fleetbase\RegistryBridge\Models\RegistryUser;
use Fleetbase\RegistryBridge\Support\Bridge;
use Fleetbase\Support\Auth;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Str;
class RegistryAuthController extends Controller
{
- public function test()
- {
- dd(Bridge::get('~/flb/extensions'));
- }
-
/**
* Authenticates a registry user based on provided credentials.
*
@@ -36,6 +34,8 @@ public function test()
*/
public function authenticate(AuthenticateRegistryUserRequest $request)
{
+ // For debug purposes
+ Log::info('Incoming authentication request from registry -> Headers: {headers} Payload: {payload}', ['headers' => $request->headers->all(), 'payload' => $request->all()]);
$identity = $request->input('identity');
$password = $request->input('password');
@@ -129,15 +129,29 @@ public function addUser(AddRegistryUserRequest $request)
*/
public function checkAccess(RegistryAuthRequest $request)
{
- // Get identity
- $identity = $request->input('identity');
+ $packageName = $request->input('package');
+ $identity = $request->input('identity');
+ $protectedPackage = Str::startsWith($packageName, config('registry-bridge.extensions.protected_prefixes'));
- // Find user by email or username
- $user = User::where('email', $identity)->orWhere('username', $identity)->first();
+ // If no identity and not a protected package allow access
+ if (!$identity && !$protectedPackage) {
+ return response()->json(['allowed' => true]);
+ }
- // If user is not admin respond with error
- if (!$user->isAdmin()) {
- return response()->error('User is not allowed access to the registry.', 401);
+ // Get registry user via identity
+ $registryUser = RegistryUser::findFromUsername($identity);
+
+ // If registry user is admin allow access
+ if ($registryUser->is_admin) {
+ return response()->json(['allowed' => true]);
+ }
+
+ // Check if package is protected, if so verify user has access to package
+ if ($protectedPackage) {
+ $extension = RegistryExtension::findByPackageName($packageName);
+ if ($extension && $extension->doesntHaveAccess($registryUser)) {
+ return response()->error('This package requires payment to access.', 401);
+ }
}
// For now only admin users can access registry
@@ -171,15 +185,16 @@ public function checkPublishAllowed(RegistryAuthRequest $request)
$force = $request->boolean('force');
$password = $request->input('password');
+ // Find user by email or username
+ $registryUser = RegistryUser::findFromUsername($identity);
+ if (!$registryUser) {
+ return response()->error('Attempting to publish extension with invalid user.', 401);
+ }
+
// If force publish bypass checks, authenticate by user login
if ($force === true) {
- // Find user by email or username
- $user = User::where(function ($query) use ($identity) {
- $query->where('email', $identity)->orWhere('phone', $identity)->orWhere('username', $identity);
- })->first();
-
// Authenticate user with password
- if (Auth::isInvalidPassword($password, $user->password)) {
+ if (Auth::isInvalidPassword($password, $registryUser->user->password)) {
return response()->error('Invalid credentials, unable to force publish.', 401);
}
@@ -197,16 +212,10 @@ public function checkPublishAllowed(RegistryAuthRequest $request)
return response()->error('Attempting to publish extension which has no record.', 401);
}
- // Find user by email or username
- $user = User::where(function ($query) use ($identity) {
- $query->where('email', $identity)->orWhere('phone', $identity)->orWhere('username', $identity);
- })->first();
- if (!$user) {
- return response()->error('Attempting to publish extension with invalid user.', 401);
- }
-
// If user is not admin respond with error
- if (!$user->isAdmin()) {
+ // For now only admin is allowed to publish to registry
+ // This may change in the future with approval/reject flow
+ if ($registryUser->isNotAdmin()) {
return response()->error('User is not allowed publish to the registry.', 401);
}
@@ -227,4 +236,91 @@ public function checkPublishAllowed(RegistryAuthRequest $request)
// Passed all checks
return response()->json(['allowed' => true]);
}
+
+ /**
+ * Creates a registry user by authenticating with the provided password.
+ *
+ * This method retrieves the current authenticated user and checks the provided password.
+ * If the password is valid, it logs in to the npm registry using the user's credentials,
+ * retrieves the authentication token, and associates it with the user. The registry token
+ * is stored in the database for the user's current session.
+ *
+ * @param Request $request the incoming HTTP request containing the user's password
+ *
+ * @return \Illuminate\Http\JsonResponse the JSON response containing the created RegistryUser or an error message
+ */
+ public function createRegistryUser(Request $request)
+ {
+ $password = $request->input('password');
+ if (!$password) {
+ return response()->error('Password is required.');
+ }
+
+ // Get current user
+ $user = Auth::getUserFromSession();
+ if (!$user) {
+ return response()->error('No user authenticated.');
+ }
+
+ // Authenticate user with password
+ if (Auth::isInvalidPassword($password, $user->password)) {
+ return response()->error('Invalid credentials.', 401);
+ }
+
+ // Create registry user
+ try {
+ $registryUser = Bridge::loginWithUser($user, $password);
+ } catch (\Throwable $e) {
+ return response()->json($e->getMessage());
+ }
+
+ return response()->json($registryUser);
+ }
+
+ /**
+ * Retrieves all registry tokens for the current company.
+ *
+ * This method queries the `RegistryUser` model to get all registry tokens
+ * associated with the current company's UUID from the session. It also includes
+ * user details for each registry token and returns the data as a JSON response.
+ *
+ * @return \Illuminate\Http\JsonResponse the JSON response containing a list of registry tokens with user details
+ */
+ public function getRegistryTokens()
+ {
+ $registryUsers = RegistryUser::select(
+ ['uuid', 'user_uuid', 'company_uuid', 'token', 'registry_token', 'expires_at', 'created_at']
+ )->where('company_uuid', session('company'))->with(
+ [
+ 'user' => function ($query) {
+ $query->select(['uuid', 'company_uuid', 'name', 'email']);
+ },
+ ]
+ )->get();
+
+ return response()->json($registryUsers);
+ }
+
+ /**
+ * Deletes a specific registry token by its UUID.
+ *
+ * This method deletes a registry token identified by its UUID. If the registry token
+ * does not exist, it returns an error response. If successful, it returns a JSON response
+ * with a status indicating the deletion was successful.
+ *
+ * @param string $id the UUID of the registry token to be deleted
+ *
+ * @return \Illuminate\Http\JsonResponse the JSON response indicating the status of the deletion
+ */
+ public function deleteRegistryToken(string $id)
+ {
+ $registryUser = RegistryUser::where('uuid', $id)->first();
+ if (!$registryUser) {
+ return response()->error('Registry token does not exist.');
+ }
+
+ $registryUser->delete();
+
+ return response()->json(['status' => 'ok']);
+ }
}
diff --git a/server/src/Http/Requests/RegistryAuthRequest.php b/server/src/Http/Requests/RegistryAuthRequest.php
index a530994..402be23 100644
--- a/server/src/Http/Requests/RegistryAuthRequest.php
+++ b/server/src/Http/Requests/RegistryAuthRequest.php
@@ -5,6 +5,7 @@
use Fleetbase\Http\Requests\FleetbaseRequest;
use Fleetbase\Models\User;
use Illuminate\Support\Facades\Validator;
+use Illuminate\Validation\Rule;
/**
* Request class to handle the addition of new registry users.
@@ -40,7 +41,8 @@ public function rules()
});
return [
- 'identity' => ['required', 'valid_identity'],
+ 'identity' => [Rule::requiredIf($this->isNotFilled('package')), 'valid_identity'],
+ 'package' => ['nullable'],
];
}
}
diff --git a/server/src/Http/Resources/RegistryUser.php b/server/src/Http/Resources/RegistryUser.php
index 8d189bd..1aa9f0a 100644
--- a/server/src/Http/Resources/RegistryUser.php
+++ b/server/src/Http/Resources/RegistryUser.php
@@ -3,7 +3,6 @@
namespace Fleetbase\RegistryBridge\Http\Resources;
use Fleetbase\Http\Resources\FleetbaseResource;
-use Fleetbase\Models\Group;
class RegistryUser extends FleetbaseResource
{
@@ -26,15 +25,4 @@ public function toArray($request)
'created_at' => $this->created_at,
];
}
-
- public function groups(): array
- {
- return collect(['$all', '$authenticated', ...data_get($this->user, 'groups', [])])->map(function ($group) {
- if ($group instanceof Group) {
- return $group->public_id;
- }
-
- return $group;
- })->toArray();
- }
}
diff --git a/server/src/Models/RegistryExtension.php b/server/src/Models/RegistryExtension.php
index 2202642..c8e1721 100644
--- a/server/src/Models/RegistryExtension.php
+++ b/server/src/Models/RegistryExtension.php
@@ -653,4 +653,44 @@ public function createStripeCheckoutSession(string $returnUri): \Stripe\Checkout
return $checkoutSession;
}
+
+ /**
+ * Determine if the registry user has access to the registry extension.
+ *
+ * This method checks if the extension requires payment. If it does not,
+ * access is granted. If payment is required, it checks if the user's company
+ * has made a purchase of the extension.
+ *
+ * @param RegistryUser $registryUser the registry user to check access for
+ *
+ * @return bool true if the user has access, false otherwise
+ */
+ public function hasAccess(RegistryUser $registryUser): bool
+ {
+ if (!$this->payment_required) {
+ return true;
+ }
+
+ return $this->purchases()->where('company_uuid', $registryUser->company_uuid)->exists();
+ }
+
+ /**
+ * Determine if the registry user does not have access to the registry extension.
+ *
+ * This method checks if the extension requires payment. If it does not,
+ * access is always denied. If payment is required, it checks if the user's
+ * company has not made a purchase of the extension.
+ *
+ * @param RegistryUser $registryUser the registry user to check access for
+ *
+ * @return bool true if the user does not have access, false otherwise
+ */
+ public function doesntHaveAccess(RegistryUser $registryUser): bool
+ {
+ if (!$this->payment_required) {
+ return false;
+ }
+
+ return $this->purchases()->where('company_uuid', $registryUser->company_uuid)->doesntExist();
+ }
}
diff --git a/server/src/Models/RegistryUser.php b/server/src/Models/RegistryUser.php
index 95ba86a..ba898c0 100644
--- a/server/src/Models/RegistryUser.php
+++ b/server/src/Models/RegistryUser.php
@@ -41,6 +41,7 @@ class RegistryUser extends Model
'company_uuid',
'user_uuid',
'token',
+ 'registry_token',
'scope',
'expires_at',
'last_used_at',
@@ -65,7 +66,7 @@ class RegistryUser extends Model
*
* @var array
*/
- protected $appends = [];
+ protected $appends = ['is_admin'];
/**
* The attributes excluded from the model's JSON form.
@@ -114,6 +115,54 @@ public function user()
return $this->belongsTo(User::class);
}
+ /**
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
+ public function extensions()
+ {
+ return $this->hasMany(RegistryExtension::class, 'company_uuid', 'company_uuid');
+ }
+
+ /**
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
+ public function purchases()
+ {
+ return $this->hasMany(RegistryExtensionPurchase::class, 'company_uuid', 'company_uuid');
+ }
+
+ /**
+ * Undocumented function.
+ */
+ public function getIsAdminAttribute(): bool
+ {
+ return $this->user->is_admin === true;
+ }
+
+ /**
+ * Determine if the user is an admin.
+ *
+ * This method checks if the `is_admin` attribute of the user is set to true.
+ *
+ * @return bool true if the user is an admin, false otherwise
+ */
+ public function isAdmin(): bool
+ {
+ return $this->is_admin === true;
+ }
+
+ /**
+ * Determine if the user is not an admin.
+ *
+ * This method checks if the `is_admin` attribute of the user is set to false.
+ *
+ * @return bool true if the user is not an admin, false otherwise
+ */
+ public function isNotAdmin(): bool
+ {
+ return $this->is_admin === false;
+ }
+
/**
* Generates a unique token for authenticating with the registry.
*
@@ -137,4 +186,65 @@ public static function generateToken(int $length = 18): string
return $token;
}
+
+ /**
+ * Find a registry user by their username.
+ *
+ * This method joins the users table with the registry users table to find a
+ * registry user by their email or username. If a matching user is found, the
+ * corresponding registry user is returned.
+ *
+ * @param string $username the username to search for
+ *
+ * @return RegistryUser|null the found registry user, or null if no user is found
+ */
+ public static function findFromUsername(string $username): ?RegistryUser
+ {
+ return static::select('registry_users.*')
+ ->join('users', function ($join) use ($username) {
+ $join->on('users.uuid', '=', 'registry_users.user_uuid')
+ ->on('users.company_uuid', '=', 'registry_users.company_uuid')
+ ->where(function ($query) use ($username) {
+ $query->where('users.email', $username)
+ ->orWhere('users.username', $username);
+ });
+ })
+ ->first();
+ }
+
+ /**
+ * Determine if the registry user can access a specific package.
+ *
+ * This method checks if the package name exists in the list of purchased
+ * extensions for the user. It verifies if the package name matches either
+ * the `package.json` or `composer.json` name in the metadata of the current bundle
+ * of any purchased extension.
+ *
+ * @param string $packageName the name of the package to check access for
+ *
+ * @return bool true if the user can access the package, false otherwise
+ */
+ public function canAccessPackage(string $packageName): bool
+ {
+ return $this->purchases()->whereHas('extension', function ($query) use ($packageName) {
+ $query->whereHas('currentBundle', function ($query) use ($packageName) {
+ $query->where('meta->package.json->name', $packageName)->orWhere('meta->composer.json->name', $packageName);
+ });
+ })->exists();
+ }
+
+ /**
+ * Retrieves the user's access groups.
+ *
+ * This method returns an array of groups that the user belongs to, including
+ * the default groups (`$all` and `$authenticated`) and the names of the purchased
+ * extension groups. The purchased extension groups are obtained by calling the
+ * `getPurchasedExtensionGroups` method.
+ *
+ * @return array an array of the user's access groups, including default and purchased extension groups
+ */
+ public function groups(): array
+ {
+ return [$this->public_id];
+ }
}
diff --git a/server/src/Providers/RegistryBridgeServiceProvider.php b/server/src/Providers/RegistryBridgeServiceProvider.php
index a032adc..6402bf4 100644
--- a/server/src/Providers/RegistryBridgeServiceProvider.php
+++ b/server/src/Providers/RegistryBridgeServiceProvider.php
@@ -37,7 +37,6 @@ class RegistryBridgeServiceProvider extends CoreServiceProvider
*/
public $middleware = [
'fleetbase.registry' => [
- 'throttle:60,1',
\Illuminate\Session\Middleware\StartSession::class,
\Fleetbase\Http\Middleware\AuthenticateOnceWithBasicAuth::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
diff --git a/server/src/Support/Bridge.php b/server/src/Support/Bridge.php
index 42715bf..e906b85 100644
--- a/server/src/Support/Bridge.php
+++ b/server/src/Support/Bridge.php
@@ -2,7 +2,14 @@
namespace Fleetbase\RegistryBridge\Support;
+use Fleetbase\Models\User;
+use Fleetbase\RegistryBridge\Models\RegistryUser;
+use Fleetbase\Support\Auth;
use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Str;
+use Symfony\Component\Process\Exception\ProcessFailedException;
+use Symfony\Component\Process\Process;
class Bridge
{
@@ -50,4 +57,120 @@ public static function post($uri, $parameters = [], $options = [])
{
return Http::withOptions($options)->post(static::createUrl($uri), $parameters);
}
+
+ /**
+ * Logs in to the npm registry using the provided user and retrieves the authentication token.
+ *
+ * This method uses the npm-cli-login tool to authenticate with the npm registry using the
+ * provided user's credentials, retrieves the authentication token from the .npmrc file,
+ * and associates it with the currently authenticated user in the application. The registry
+ * token is stored in the database for the user's current session.
+ *
+ * @param User $user the fleetbase user model containing the username and email
+ * @param string $password the npm password for the user
+ *
+ * @return RegistryUser the RegistryUser model containing the registry token and associated data
+ *
+ * @throws \Exception If there is no active session, the .npmrc file is not found, the auth token is not found, or the npm login fails.
+ */
+ public static function loginWithUser(User $user, string $password): RegistryUser
+ {
+ return static::login($user->username, $password, $user->email);
+ }
+
+ /**
+ * Logs in to the fleetbase registry and retrieves the authentication token.
+ *
+ * This method uses the npm-cli-login tool to authenticate with the fleetbase registry,
+ * retrieves the authentication token from the .npmrc file, and associates it with
+ * the currently authenticated user in the application. The registry token is stored
+ * in the database for the user's current session.
+ *
+ * @param string $username the npm username
+ * @param string $password the npm password
+ * @param string $email the npm email
+ *
+ * @return RegistryUser the RegistryUser model containing the registry token and associated data
+ *
+ * @throws \Exception If there is no active session, the .npmrc file is not found, the auth token is not found, or the npm login fails.
+ */
+ public static function login(string $username, string $password, string $email): RegistryUser
+ {
+ // Session is required
+ if (session()->missing(['company', 'user'])) {
+ throw new \Exception('No active session to create registry token for.');
+ }
+
+ // Get registry
+ $registry = static::createUrl();
+
+ // Set .npmrc path
+ $npmrcPath = 'tmp/.npmrc-' . session('user');
+
+ // Create .npmrc file
+ Storage::disk('local')->put($npmrcPath, '');
+
+ // Prepare command
+ $process = new Process([
+ 'npm-cli-login',
+ '-u', $username,
+ '-p', $password,
+ '-e', $email,
+ '-r', $registry,
+ '-s', 'false',
+ '--config-path', storage_path('app/' . $npmrcPath),
+ ]);
+
+ // Set timeout
+ $process->setTimeout(60);
+
+ try {
+ // Run the process
+ $process->mustRun();
+
+ // Check if .npmrc file exists
+ if (!Storage::drive('local')->exists($npmrcPath)) {
+ throw new \Exception('.npmrc file not found');
+ }
+
+ // Remove protocol from registry URL for matching
+ $registryHost = preg_replace('/^https?:\/\//', '', $registry);
+
+ // Read the .npmrc file to get the auth token
+ $npmrcContent = Storage::drive('local')->get($npmrcPath);
+ $lines = explode("\n", $npmrcContent);
+ $authToken = null;
+
+ foreach ($lines as $line) {
+ $line = trim($line);
+ if (Str::contains($line, $registryHost) && Str::contains($line, '_authToken=')) {
+ $parts = explode('_authToken=', $line);
+ if (count($parts) === 2) {
+ $authToken = trim($parts[1], ' "');
+ break;
+ }
+ }
+ }
+
+ // Delete .npmrc file
+ Storage::drive('local')->delete($npmrcPath);
+
+ if ($authToken) {
+ // Get current authenticated user
+ $user = Auth::getUserFromSession();
+
+ // Create or update registry user for current session
+ $registryUser = RegistryUser::updateOrCreate(
+ ['company_uuid' => session('company'), 'user_uuid' => $user->uuid],
+ ['registry_token' => $authToken, 'scope' => '*', 'expires_at' => now()->addYear(), 'name' => $user->public_id . ' developer token']
+ );
+
+ return $registryUser;
+ }
+
+ throw new \Exception('Auth token not found in .npmrc');
+ } catch (ProcessFailedException $exception) {
+ throw new \Exception('npm login failed: ' . $exception->getMessage());
+ }
+ }
}
diff --git a/server/src/routes.php b/server/src/routes.php
index 7c0c11f..87d4ecd 100644
--- a/server/src/routes.php
+++ b/server/src/routes.php
@@ -13,45 +13,56 @@
|
*/
-Route::get('~registry/test', 'Fleetbase\RegistryBridge\Http\Controllers\Internal\v1\RegistryAuthController@test');
-
Route::prefix(config('internals.api.routing.prefix', '~registry'))->middleware(['fleetbase.registry'])->namespace('Fleetbase\RegistryBridge\Http\Controllers')->group(
function ($router) {
/*
* Internal Routes v1
*/
$router->group(['prefix' => config('internals.api.routing.internal_prefix', 'v1'), 'namespace' => 'Internal\v1'], function ($router) {
- $router->get('categories', 'RegistryController@categories');
- $router->get('engines', 'RegistryController@getInstalledEngines');
- $router->group(['prefix' => 'installer'], function ($router) {
- $router->post('install', 'ExtensionInstallerController@install');
- $router->post('uninstall', 'ExtensionInstallerController@uninstall');
- });
$router->group(['prefix' => 'auth'], function ($router) {
- $router->post('authenticate', 'RegistryAuthController@authenticate');
- $router->post('add-user', 'RegistryAuthController@addUser');
- $router->post('check-access', 'RegistryAuthController@checkAccess');
- $router->post('check-publish', 'RegistryAuthController@checkPublishAllowed');
- });
- $router->group(['prefix' => 'payments'], function ($router) {
- $router->post('account', 'RegistryPaymentsController@getStripeAccount');
- $router->post('account-session', 'RegistryPaymentsController@getStripeAccountSession');
- $router->get('has-stripe-connect-account', 'RegistryPaymentsController@hasStripeConnectAccount');
- $router->post('create-checkout-session', 'RegistryPaymentsController@createStripeCheckoutSession');
- $router->post('get-checkout-session', 'RegistryPaymentsController@getStripeCheckoutSessionStatus');
- $router->get('author-received', 'RegistryPaymentsController@getAuthorReceivedPayments');
- });
- $router->fleetbaseRoutes('registry-extensions', function ($router, $controller) {
- $router->post('{id}/submit', $controller('submit'));
- $router->post('approve', $controller('approve'));
- $router->post('reject', $controller('reject'));
- $router->get('download-bundle', $controller('downloadBundle'));
- $router->get('analytics', $controller('analytics'));
- $router->get('installed', $controller('installed'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
- $router->get('purchased', $controller('purchased'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
+ $router->group(['middleware' => ['fleetbase.protected', 'throttle:60,1']], function ($router) {
+ $router->get('registry-tokens', 'RegistryAuthController@getRegistryTokens');
+ $router->delete('registry-tokens/{id}', 'RegistryAuthController@deleteRegistryToken');
+ $router->post('registry-tokens', 'RegistryAuthController@createRegistryUser');
+ });
+
+ $router->post('authenticate', 'RegistryAuthController@authenticate')->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
+ $router->post('add-user', 'RegistryAuthController@addUser')->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
+ $router->post('check-access', 'RegistryAuthController@checkAccess')->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
+ $router->post('check-publish', 'RegistryAuthController@checkPublishAllowed')->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
});
- $router->fleetbaseRoutes('registry-extension-bundles', function ($router, $controller) {
- $router->get('download', $controller('download'));
+
+ $router->group(['middleware' => ['fleetbase.protected', 'throttle:60,1']], function ($router) {
+ $router->get('categories', 'RegistryController@categories');
+ $router->get('engines', 'RegistryController@getInstalledEngines');
+
+ $router->group(['prefix' => 'installer'], function ($router) {
+ $router->post('install', 'ExtensionInstallerController@install');
+ $router->post('uninstall', 'ExtensionInstallerController@uninstall');
+ });
+
+ $router->group(['prefix' => 'payments'], function ($router) {
+ $router->post('account', 'RegistryPaymentsController@getStripeAccount');
+ $router->post('account-session', 'RegistryPaymentsController@getStripeAccountSession');
+ $router->get('has-stripe-connect-account', 'RegistryPaymentsController@hasStripeConnectAccount');
+ $router->post('create-checkout-session', 'RegistryPaymentsController@createStripeCheckoutSession');
+ $router->post('get-checkout-session', 'RegistryPaymentsController@getStripeCheckoutSessionStatus');
+ $router->get('author-received', 'RegistryPaymentsController@getAuthorReceivedPayments');
+ });
+
+ $router->fleetbaseRoutes('registry-extensions', function ($router, $controller) {
+ $router->post('{id}/submit', $controller('submit'));
+ $router->post('approve', $controller('approve'));
+ $router->post('reject', $controller('reject'));
+ $router->get('download-bundle', $controller('downloadBundle'));
+ $router->get('analytics', $controller('analytics'));
+ $router->get('installed', $controller('installed'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
+ $router->get('purchased', $controller('purchased'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]);
+ });
+
+ $router->fleetbaseRoutes('registry-extension-bundles', function ($router, $controller) {
+ $router->get('download', $controller('download'));
+ });
});
});
}
diff --git a/tests/integration/components/modals/create-registry-credentials-test.js b/tests/integration/components/modals/create-registry-credentials-test.js
new file mode 100644
index 0000000..131d56c
--- /dev/null
+++ b/tests/integration/components/modals/create-registry-credentials-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | modals/create-registry-credentials', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs``);
+
+ assert.dom().hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom().hasText('template block text');
+ });
+});
diff --git a/tests/unit/controllers/developers/credentials-test.js b/tests/unit/controllers/developers/credentials-test.js
new file mode 100644
index 0000000..f14a7ba
--- /dev/null
+++ b/tests/unit/controllers/developers/credentials-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Controller | developers/credentials', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup('controller:developers/credentials');
+ assert.ok(controller);
+ });
+});