generateTestAccount($permissions); $response = $this->actingAs($user)->postJson($this->link($server) . '/users', [ 'email' => $email = $this->faker->email, 'permissions' => [ Permission::ACTION_USER_CREATE, ], ]); $response->assertOk(); /** @var User $subuser */ $subuser = User::query()->where('email', $email)->firstOrFail(); $response->assertJsonPath('object', Subuser::RESOURCE_NAME); $response->assertJsonPath('attributes.uuid', $subuser->uuid); $response->assertJsonPath('attributes.permissions', [ Permission::ACTION_USER_CREATE, Permission::ACTION_WEBSOCKET_CONNECT, ]); $expected = $response->json('attributes'); unset($expected['permissions']); $this->assertJsonTransformedWith($expected, $subuser); } /** * Test that a newly created user account correctly causes the creation of a user:user.create * activity log entry. */ public function testCreatingSubuserWithNewEmailLogsUserCreation() { [$user, $server] = $this->generateTestAccount(); $response = $this->actingAs($user)->postJson($this->link($server) . '/users', [ 'email' => $email = $this->faker->email, 'permissions' => [ Permission::ACTION_USER_CREATE, ], ]); $response->assertOk(); /** @var User $subuser */ $subuser = User::query()->where('email', $email)->firstOrFail(); $this->assertActivityLogged('user:user.create'); $this->assertDatabaseHas('activity_logs', [ 'event' => 'user:user.create', 'actor_type' => $user->getMorphClass(), 'actor_id' => $user->id, ]); } /** * Tests that an error is returned if a subuser attempts to create a new subuser and assign * permissions that their account does not also possess. */ public function testErrorIsReturnedIfAssigningPermissionsNotAssignedToSelf() { [$user, $server] = $this->generateTestAccount([ Permission::ACTION_USER_CREATE, Permission::ACTION_USER_READ, Permission::ACTION_CONTROL_CONSOLE, ]); $response = $this->actingAs($user)->postJson($this->link($server) . '/users', [ 'email' => $this->faker->email, 'permissions' => [ Permission::ACTION_USER_CREATE, Permission::ACTION_USER_UPDATE, // This permission is not assigned to the subuser. ], ]); $response->assertForbidden(); $response->assertJsonPath('errors.0.code', 'HttpForbiddenException'); $response->assertJsonPath('errors.0.detail', 'Cannot assign permissions to a subuser that your account does not actively possess.'); } /** * Throws some bad data at the API and ensures that a subuser cannot be created. */ public function testSubuserWithExcessivelyLongEmailCannotBeCreated() { [$user, $server] = $this->generateTestAccount(); /* * RFCs limit certain parts of an email to certain character limits. * * A limit of <= 64 for the local, then <= 63 for each domain label. * We will stay below the limit to make sure we're within the 191 column limit for emails. */ $local = str_repeat(Str::random(10), 6) . '1234'; $label = str_repeat(Str::random(10), 6) . '1'; // Make sure we're within the column limit $email = "$local@$label.$label.au"; $this->assertSame(64, strlen($local)); $this->assertSame(61, strlen($label)); $this->assertSame(191, strlen($email)); $response = $this->actingAs($user)->postJson($this->link($server) . '/users', [ 'email' => $email, 'permissions' => [ Permission::ACTION_USER_CREATE, ], ]); $response->assertOk(); // Exceed column limit of 1 >= and <= 191 $email = "$local@$label.$label.com"; $this->assertSame(192, strlen($email)); $response = $this->actingAs($user)->postJson($this->link($server) . '/users', [ 'email' => $email, 'permissions' => [ Permission::ACTION_USER_CREATE, ], ]); $response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY); $response->assertJsonPath('errors.0.detail', 'The email must be between 1 and 191 characters.'); $response->assertJsonPath('errors.0.meta.source_field', 'email'); } /** * Test that creating a subuser when there is already an account with that email runs * as expected and does not create a new account. */ public function testCreatingSubuserWithSameEmailAsExistingUserWorks() { [$user, $server] = $this->generateTestAccount(); /** @var User $existing */ $existing = User::factory()->create(['email' => $this->faker->email]); $response = $this->actingAs($user)->postJson($this->link($server) . '/users', [ 'email' => $existing->email, 'permissions' => [ Permission::ACTION_USER_CREATE, ], ]); $response->assertOk(); $response->assertJsonPath('object', Subuser::RESOURCE_NAME); $response->assertJsonPath('attributes.uuid', $existing->uuid); } /** * Test that an error is returned if the account associated with an email address is already * associated with the server instance. */ public function testAddingSubuserThatAlreadyIsAssignedReturnsError() { [$user, $server] = $this->generateTestAccount(); $response = $this->actingAs($user)->postJson($this->link($server) . '/users', [ 'email' => $email = $this->faker->email, 'permissions' => [ Permission::ACTION_USER_CREATE, ], ]); $response->assertOk(); $response = $this->actingAs($user)->postJson($this->link($server) . '/users', [ 'email' => $email, 'permissions' => [ Permission::ACTION_USER_CREATE, ], ]); $response->assertStatus(Response::HTTP_BAD_REQUEST); $response->assertJsonPath('errors.0.code', 'ServerSubuserExistsException'); $response->assertJsonPath('errors.0.detail', 'A user with that email address is already assigned as a subuser for this server.'); } public static function permissionsDataProvider(): array { return [[[]], [[Permission::ACTION_USER_CREATE]]]; } }