diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts
index 5bf81761ed6..340e8f567cb 100644
--- a/libs/angular/src/services/jslib-services.module.ts
+++ b/libs/angular/src/services/jslib-services.module.ts
@@ -178,6 +178,7 @@ import { BulkEncryptServiceImplementation } from "@bitwarden/common/platform/ser
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation";
import { DefaultBroadcasterService } from "@bitwarden/common/platform/services/default-broadcaster.service";
import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.service";
+import { DefaultServerSettingsService } from "@bitwarden/common/platform/services/default-server-settings.service";
import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service";
import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service";
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
@@ -1322,6 +1323,11 @@ const safeProviders: SafeProvider[] = [
InternalUserDecryptionOptionsServiceAbstraction,
],
}),
+ safeProvider({
+ provide: DefaultServerSettingsService,
+ useClass: DefaultServerSettingsService,
+ deps: [ConfigService],
+ }),
safeProvider({
provide: RegisterRouteService,
useClass: RegisterRouteService,
diff --git a/libs/auth/src/angular/login/login-secondary-content.component.ts b/libs/auth/src/angular/login/login-secondary-content.component.ts
index abc772b6c14..dbc9535e67a 100644
--- a/libs/auth/src/angular/login/login-secondary-content.component.ts
+++ b/libs/auth/src/angular/login/login-secondary-content.component.ts
@@ -4,13 +4,14 @@ import { RouterModule } from "@angular/router";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { RegisterRouteService } from "@bitwarden/auth/common";
+import { DefaultServerSettingsService } from "@bitwarden/common/platform/services/default-server-settings.service";
import { LinkModule } from "@bitwarden/components";
@Component({
standalone: true,
imports: [CommonModule, JslibModule, LinkModule, RouterModule],
template: `
-
+
{{ "newToBitwarden" | i18n }}
{{ "createAccount" | i18n }}
@@ -18,7 +19,10 @@ import { LinkModule } from "@bitwarden/components";
})
export class LoginSecondaryContentComponent {
registerRouteService = inject(RegisterRouteService);
+ serverSettingsService = inject(DefaultServerSettingsService);
// TODO: remove when email verification flag is removed
protected registerRoute$ = this.registerRouteService.registerRoute$();
+
+ protected isUserRegistrationDisabled$ = this.serverSettingsService.isUserRegistrationDisabled$;
}
diff --git a/libs/common/src/platform/abstractions/config/config.service.ts b/libs/common/src/platform/abstractions/config/config.service.ts
index 9b16cee3854..05a3dcd148c 100644
--- a/libs/common/src/platform/abstractions/config/config.service.ts
+++ b/libs/common/src/platform/abstractions/config/config.service.ts
@@ -3,6 +3,7 @@ import { SemVer } from "semver";
import { FeatureFlag, FeatureFlagValueType } from "../../../enums/feature-flag.enum";
import { UserId } from "../../../types/guid";
+import { ServerSettings } from "../../models/domain/server-settings";
import { Region } from "../environment.service";
import { ServerConfig } from "./server-config";
@@ -10,6 +11,8 @@ import { ServerConfig } from "./server-config";
export abstract class ConfigService {
/** The server config of the currently active user */
serverConfig$: Observable
;
+ /** The server settings of the currently active user */
+ serverSettings$: Observable;
/** The cloud region of the currently active user */
cloudRegion$: Observable;
/**
diff --git a/libs/common/src/platform/abstractions/config/server-config.ts b/libs/common/src/platform/abstractions/config/server-config.ts
index bb186059641..b51628cbf5b 100644
--- a/libs/common/src/platform/abstractions/config/server-config.ts
+++ b/libs/common/src/platform/abstractions/config/server-config.ts
@@ -6,6 +6,7 @@ import {
ThirdPartyServerConfigData,
EnvironmentServerConfigData,
} from "../../models/data/server-config.data";
+import { ServerSettings } from "../../models/domain/server-settings";
const dayInMilliseconds = 24 * 3600 * 1000;
@@ -16,6 +17,7 @@ export class ServerConfig {
environment?: EnvironmentServerConfigData;
utcDate: Date;
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
+ settings: ServerSettings;
constructor(serverConfigData: ServerConfigData) {
this.version = serverConfigData.version;
@@ -24,6 +26,7 @@ export class ServerConfig {
this.utcDate = new Date(serverConfigData.utcDate);
this.environment = serverConfigData.environment;
this.featureStates = serverConfigData.featureStates;
+ this.settings = serverConfigData.settings;
if (this.server?.name == null && this.server?.url == null) {
this.server = null;
diff --git a/libs/common/src/platform/models/data/server-config.data.spec.ts b/libs/common/src/platform/models/data/server-config.data.spec.ts
index b94092662a6..13d14204085 100644
--- a/libs/common/src/platform/models/data/server-config.data.spec.ts
+++ b/libs/common/src/platform/models/data/server-config.data.spec.ts
@@ -16,6 +16,9 @@ describe("ServerConfigData", () => {
name: "test",
url: "https://test.com",
},
+ settings: {
+ disableUserRegistration: false,
+ },
environment: {
cloudRegion: Region.EU,
vault: "https://vault.com",
diff --git a/libs/common/src/platform/models/data/server-config.data.ts b/libs/common/src/platform/models/data/server-config.data.ts
index 57e8fbc6284..d5f17fd0ace 100644
--- a/libs/common/src/platform/models/data/server-config.data.ts
+++ b/libs/common/src/platform/models/data/server-config.data.ts
@@ -2,6 +2,7 @@ import { Jsonify } from "type-fest";
import { AllowedFeatureFlagTypes } from "../../../enums/feature-flag.enum";
import { Region } from "../../abstractions/environment.service";
+import { ServerSettings } from "../domain/server-settings";
import {
ServerConfigResponse,
ThirdPartyServerConfigResponse,
@@ -15,6 +16,7 @@ export class ServerConfigData {
environment?: EnvironmentServerConfigData;
utcDate: string;
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
+ settings: ServerSettings;
constructor(serverConfigResponse: Partial) {
this.version = serverConfigResponse?.version;
@@ -27,6 +29,7 @@ export class ServerConfigData {
? new EnvironmentServerConfigData(serverConfigResponse.environment)
: null;
this.featureStates = serverConfigResponse?.featureStates;
+ this.settings = new ServerSettings(serverConfigResponse.settings);
}
static fromJSON(obj: Jsonify): ServerConfigData {
diff --git a/libs/common/src/platform/models/domain/server-settings.spec.ts b/libs/common/src/platform/models/domain/server-settings.spec.ts
new file mode 100644
index 00000000000..3e6295fa5c4
--- /dev/null
+++ b/libs/common/src/platform/models/domain/server-settings.spec.ts
@@ -0,0 +1,20 @@
+import { ServerSettings } from "./server-settings";
+
+describe("ServerSettings", () => {
+ describe("disableUserRegistration", () => {
+ it("defaults disableUserRegistration to false", () => {
+ const settings = new ServerSettings();
+ expect(settings.disableUserRegistration).toBe(false);
+ });
+
+ it("sets disableUserRegistration to true when provided", () => {
+ const settings = new ServerSettings({ disableUserRegistration: true });
+ expect(settings.disableUserRegistration).toBe(true);
+ });
+
+ it("sets disableUserRegistration to false when provided", () => {
+ const settings = new ServerSettings({ disableUserRegistration: false });
+ expect(settings.disableUserRegistration).toBe(false);
+ });
+ });
+});
diff --git a/libs/common/src/platform/models/domain/server-settings.ts b/libs/common/src/platform/models/domain/server-settings.ts
new file mode 100644
index 00000000000..b18f07466d7
--- /dev/null
+++ b/libs/common/src/platform/models/domain/server-settings.ts
@@ -0,0 +1,7 @@
+export class ServerSettings {
+ disableUserRegistration: boolean;
+
+ constructor(data?: ServerSettings) {
+ this.disableUserRegistration = data?.disableUserRegistration ?? false;
+ }
+}
diff --git a/libs/common/src/platform/models/response/server-config.response.ts b/libs/common/src/platform/models/response/server-config.response.ts
index a546d2d3de7..d295634830a 100644
--- a/libs/common/src/platform/models/response/server-config.response.ts
+++ b/libs/common/src/platform/models/response/server-config.response.ts
@@ -1,6 +1,7 @@
import { AllowedFeatureFlagTypes } from "../../../enums/feature-flag.enum";
import { BaseResponse } from "../../../models/response/base.response";
import { Region } from "../../abstractions/environment.service";
+import { ServerSettings } from "../domain/server-settings";
export class ServerConfigResponse extends BaseResponse {
version: string;
@@ -8,6 +9,7 @@ export class ServerConfigResponse extends BaseResponse {
server: ThirdPartyServerConfigResponse;
environment: EnvironmentServerConfigResponse;
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
+ settings: ServerSettings;
constructor(response: any) {
super(response);
@@ -21,6 +23,7 @@ export class ServerConfigResponse extends BaseResponse {
this.server = new ThirdPartyServerConfigResponse(this.getResponseProperty("Server"));
this.environment = new EnvironmentServerConfigResponse(this.getResponseProperty("Environment"));
this.featureStates = this.getResponseProperty("FeatureStates");
+ this.settings = new ServerSettings(this.getResponseProperty("Settings"));
}
}
diff --git a/libs/common/src/platform/services/config/default-config.service.ts b/libs/common/src/platform/services/config/default-config.service.ts
index e0603ed509b..fce1c12106f 100644
--- a/libs/common/src/platform/services/config/default-config.service.ts
+++ b/libs/common/src/platform/services/config/default-config.service.ts
@@ -28,6 +28,7 @@ import { Environment, EnvironmentService, Region } from "../../abstractions/envi
import { LogService } from "../../abstractions/log.service";
import { devFlagEnabled, devFlagValue } from "../../misc/flags";
import { ServerConfigData } from "../../models/data/server-config.data";
+import { ServerSettings } from "../../models/domain/server-settings";
import { CONFIG_DISK, KeyDefinition, StateProvider, UserKeyDefinition } from "../../state";
export const RETRIEVAL_INTERVAL = devFlagEnabled("configRetrievalIntervalMs")
@@ -57,6 +58,8 @@ export class DefaultConfigService implements ConfigService {
serverConfig$: Observable;
+ serverSettings$: Observable;
+
cloudRegion$: Observable;
constructor(
@@ -111,6 +114,10 @@ export class DefaultConfigService implements ConfigService {
this.cloudRegion$ = this.serverConfig$.pipe(
map((config) => config?.environment?.cloudRegion ?? Region.US),
);
+
+ this.serverSettings$ = this.serverConfig$.pipe(
+ map((config) => config?.settings ?? new ServerSettings()),
+ );
}
getFeatureFlag$(key: Flag) {
diff --git a/libs/common/src/platform/services/default-server-settings.service.spec.ts b/libs/common/src/platform/services/default-server-settings.service.spec.ts
new file mode 100644
index 00000000000..09bca2ff786
--- /dev/null
+++ b/libs/common/src/platform/services/default-server-settings.service.spec.ts
@@ -0,0 +1,47 @@
+import { of } from "rxjs";
+
+import { ConfigService } from "../abstractions/config/config.service";
+import { ServerSettings } from "../models/domain/server-settings";
+
+import { DefaultServerSettingsService } from "./default-server-settings.service";
+
+describe("DefaultServerSettingsService", () => {
+ let service: DefaultServerSettingsService;
+ let configServiceMock: { serverSettings$: any };
+
+ beforeEach(() => {
+ configServiceMock = { serverSettings$: of() };
+ service = new DefaultServerSettingsService(configServiceMock as ConfigService);
+ });
+
+ describe("getSettings$", () => {
+ it("returns server settings", () => {
+ const mockSettings = new ServerSettings({ disableUserRegistration: true });
+ configServiceMock.serverSettings$ = of(mockSettings);
+
+ service.getSettings$().subscribe((settings) => {
+ expect(settings).toEqual(mockSettings);
+ });
+ });
+ });
+
+ describe("isUserRegistrationDisabled$", () => {
+ it("returns true when user registration is disabled", () => {
+ const mockSettings = new ServerSettings({ disableUserRegistration: true });
+ configServiceMock.serverSettings$ = of(mockSettings);
+
+ service.isUserRegistrationDisabled$.subscribe((isDisabled: boolean) => {
+ expect(isDisabled).toBe(true);
+ });
+ });
+
+ it("returns false when user registration is enabled", () => {
+ const mockSettings = new ServerSettings({ disableUserRegistration: false });
+ configServiceMock.serverSettings$ = of(mockSettings);
+
+ service.isUserRegistrationDisabled$.subscribe((isDisabled: boolean) => {
+ expect(isDisabled).toBe(false);
+ });
+ });
+ });
+});
diff --git a/libs/common/src/platform/services/default-server-settings.service.ts b/libs/common/src/platform/services/default-server-settings.service.ts
new file mode 100644
index 00000000000..9d0dd4bfd94
--- /dev/null
+++ b/libs/common/src/platform/services/default-server-settings.service.ts
@@ -0,0 +1,19 @@
+import { Observable } from "rxjs";
+import { map } from "rxjs/operators";
+
+import { ConfigService } from "../abstractions/config/config.service";
+import { ServerSettings } from "../models/domain/server-settings";
+
+export class DefaultServerSettingsService {
+ constructor(private configService: ConfigService) {}
+
+ getSettings$(): Observable {
+ return this.configService.serverSettings$;
+ }
+
+ get isUserRegistrationDisabled$(): Observable {
+ return this.getSettings$().pipe(
+ map((settings: ServerSettings) => settings.disableUserRegistration),
+ );
+ }
+}