mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-02 18:17:46 +01:00
[PM-5237] Clients, Self Hosted: Login - Hide "Create account" when registration disabled (#11811)
* Add server settings model and service. * Inject ServerSettingsService into the login-secondary-content component. * Fix merge conflict * Add server settings to old views * Remove server settings from desktop/mobile * Cleanup unused code * Remove changes to default config * Conditionally show/hide HR element * Add tests * PM-5237 - Move ServerSettingsService to jslib-services.module so it is the same across all clients and to solve NullInjectorErrors on desktop & browser extension * Remove change to v1 components * Rename ServerSettingsService to DefaultServerSettingsService * Remove unnecessary map call * Remove server interface in favor of using ServerSettings class * Add back HR element --------- Co-authored-by: Jared Snider <jsnider@bitwarden.com>
This commit is contained in:
parent
1afb2f7769
commit
f5e6fc8ed5
@ -178,6 +178,7 @@ import { BulkEncryptServiceImplementation } from "@bitwarden/common/platform/ser
|
|||||||
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation";
|
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation";
|
||||||
import { DefaultBroadcasterService } from "@bitwarden/common/platform/services/default-broadcaster.service";
|
import { DefaultBroadcasterService } from "@bitwarden/common/platform/services/default-broadcaster.service";
|
||||||
import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.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 { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service";
|
||||||
import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service";
|
import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service";
|
||||||
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
|
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
|
||||||
@ -1322,6 +1323,11 @@ const safeProviders: SafeProvider[] = [
|
|||||||
InternalUserDecryptionOptionsServiceAbstraction,
|
InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: DefaultServerSettingsService,
|
||||||
|
useClass: DefaultServerSettingsService,
|
||||||
|
deps: [ConfigService],
|
||||||
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: RegisterRouteService,
|
provide: RegisterRouteService,
|
||||||
useClass: RegisterRouteService,
|
useClass: RegisterRouteService,
|
||||||
|
@ -4,13 +4,14 @@ import { RouterModule } from "@angular/router";
|
|||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { RegisterRouteService } from "@bitwarden/auth/common";
|
import { RegisterRouteService } from "@bitwarden/auth/common";
|
||||||
|
import { DefaultServerSettingsService } from "@bitwarden/common/platform/services/default-server-settings.service";
|
||||||
import { LinkModule } from "@bitwarden/components";
|
import { LinkModule } from "@bitwarden/components";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, JslibModule, LinkModule, RouterModule],
|
imports: [CommonModule, JslibModule, LinkModule, RouterModule],
|
||||||
template: `
|
template: `
|
||||||
<div class="tw-text-center">
|
<div class="tw-text-center" *ngIf="!(isUserRegistrationDisabled$ | async)">
|
||||||
{{ "newToBitwarden" | i18n }}
|
{{ "newToBitwarden" | i18n }}
|
||||||
<a bitLink [routerLink]="registerRoute$ | async">{{ "createAccount" | i18n }}</a>
|
<a bitLink [routerLink]="registerRoute$ | async">{{ "createAccount" | i18n }}</a>
|
||||||
</div>
|
</div>
|
||||||
@ -18,7 +19,10 @@ import { LinkModule } from "@bitwarden/components";
|
|||||||
})
|
})
|
||||||
export class LoginSecondaryContentComponent {
|
export class LoginSecondaryContentComponent {
|
||||||
registerRouteService = inject(RegisterRouteService);
|
registerRouteService = inject(RegisterRouteService);
|
||||||
|
serverSettingsService = inject(DefaultServerSettingsService);
|
||||||
|
|
||||||
// TODO: remove when email verification flag is removed
|
// TODO: remove when email verification flag is removed
|
||||||
protected registerRoute$ = this.registerRouteService.registerRoute$();
|
protected registerRoute$ = this.registerRouteService.registerRoute$();
|
||||||
|
|
||||||
|
protected isUserRegistrationDisabled$ = this.serverSettingsService.isUserRegistrationDisabled$;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { SemVer } from "semver";
|
|||||||
|
|
||||||
import { FeatureFlag, FeatureFlagValueType } from "../../../enums/feature-flag.enum";
|
import { FeatureFlag, FeatureFlagValueType } from "../../../enums/feature-flag.enum";
|
||||||
import { UserId } from "../../../types/guid";
|
import { UserId } from "../../../types/guid";
|
||||||
|
import { ServerSettings } from "../../models/domain/server-settings";
|
||||||
import { Region } from "../environment.service";
|
import { Region } from "../environment.service";
|
||||||
|
|
||||||
import { ServerConfig } from "./server-config";
|
import { ServerConfig } from "./server-config";
|
||||||
@ -10,6 +11,8 @@ import { ServerConfig } from "./server-config";
|
|||||||
export abstract class ConfigService {
|
export abstract class ConfigService {
|
||||||
/** The server config of the currently active user */
|
/** The server config of the currently active user */
|
||||||
serverConfig$: Observable<ServerConfig | null>;
|
serverConfig$: Observable<ServerConfig | null>;
|
||||||
|
/** The server settings of the currently active user */
|
||||||
|
serverSettings$: Observable<ServerSettings | null>;
|
||||||
/** The cloud region of the currently active user */
|
/** The cloud region of the currently active user */
|
||||||
cloudRegion$: Observable<Region>;
|
cloudRegion$: Observable<Region>;
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
ThirdPartyServerConfigData,
|
ThirdPartyServerConfigData,
|
||||||
EnvironmentServerConfigData,
|
EnvironmentServerConfigData,
|
||||||
} from "../../models/data/server-config.data";
|
} from "../../models/data/server-config.data";
|
||||||
|
import { ServerSettings } from "../../models/domain/server-settings";
|
||||||
|
|
||||||
const dayInMilliseconds = 24 * 3600 * 1000;
|
const dayInMilliseconds = 24 * 3600 * 1000;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ export class ServerConfig {
|
|||||||
environment?: EnvironmentServerConfigData;
|
environment?: EnvironmentServerConfigData;
|
||||||
utcDate: Date;
|
utcDate: Date;
|
||||||
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
|
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
|
||||||
|
settings: ServerSettings;
|
||||||
|
|
||||||
constructor(serverConfigData: ServerConfigData) {
|
constructor(serverConfigData: ServerConfigData) {
|
||||||
this.version = serverConfigData.version;
|
this.version = serverConfigData.version;
|
||||||
@ -24,6 +26,7 @@ export class ServerConfig {
|
|||||||
this.utcDate = new Date(serverConfigData.utcDate);
|
this.utcDate = new Date(serverConfigData.utcDate);
|
||||||
this.environment = serverConfigData.environment;
|
this.environment = serverConfigData.environment;
|
||||||
this.featureStates = serverConfigData.featureStates;
|
this.featureStates = serverConfigData.featureStates;
|
||||||
|
this.settings = serverConfigData.settings;
|
||||||
|
|
||||||
if (this.server?.name == null && this.server?.url == null) {
|
if (this.server?.name == null && this.server?.url == null) {
|
||||||
this.server = null;
|
this.server = null;
|
||||||
|
@ -16,6 +16,9 @@ describe("ServerConfigData", () => {
|
|||||||
name: "test",
|
name: "test",
|
||||||
url: "https://test.com",
|
url: "https://test.com",
|
||||||
},
|
},
|
||||||
|
settings: {
|
||||||
|
disableUserRegistration: false,
|
||||||
|
},
|
||||||
environment: {
|
environment: {
|
||||||
cloudRegion: Region.EU,
|
cloudRegion: Region.EU,
|
||||||
vault: "https://vault.com",
|
vault: "https://vault.com",
|
||||||
|
@ -2,6 +2,7 @@ import { Jsonify } from "type-fest";
|
|||||||
|
|
||||||
import { AllowedFeatureFlagTypes } from "../../../enums/feature-flag.enum";
|
import { AllowedFeatureFlagTypes } from "../../../enums/feature-flag.enum";
|
||||||
import { Region } from "../../abstractions/environment.service";
|
import { Region } from "../../abstractions/environment.service";
|
||||||
|
import { ServerSettings } from "../domain/server-settings";
|
||||||
import {
|
import {
|
||||||
ServerConfigResponse,
|
ServerConfigResponse,
|
||||||
ThirdPartyServerConfigResponse,
|
ThirdPartyServerConfigResponse,
|
||||||
@ -15,6 +16,7 @@ export class ServerConfigData {
|
|||||||
environment?: EnvironmentServerConfigData;
|
environment?: EnvironmentServerConfigData;
|
||||||
utcDate: string;
|
utcDate: string;
|
||||||
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
|
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
|
||||||
|
settings: ServerSettings;
|
||||||
|
|
||||||
constructor(serverConfigResponse: Partial<ServerConfigResponse>) {
|
constructor(serverConfigResponse: Partial<ServerConfigResponse>) {
|
||||||
this.version = serverConfigResponse?.version;
|
this.version = serverConfigResponse?.version;
|
||||||
@ -27,6 +29,7 @@ export class ServerConfigData {
|
|||||||
? new EnvironmentServerConfigData(serverConfigResponse.environment)
|
? new EnvironmentServerConfigData(serverConfigResponse.environment)
|
||||||
: null;
|
: null;
|
||||||
this.featureStates = serverConfigResponse?.featureStates;
|
this.featureStates = serverConfigResponse?.featureStates;
|
||||||
|
this.settings = new ServerSettings(serverConfigResponse.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Jsonify<ServerConfigData>): ServerConfigData {
|
static fromJSON(obj: Jsonify<ServerConfigData>): ServerConfigData {
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
export class ServerSettings {
|
||||||
|
disableUserRegistration: boolean;
|
||||||
|
|
||||||
|
constructor(data?: ServerSettings) {
|
||||||
|
this.disableUserRegistration = data?.disableUserRegistration ?? false;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { AllowedFeatureFlagTypes } from "../../../enums/feature-flag.enum";
|
import { AllowedFeatureFlagTypes } from "../../../enums/feature-flag.enum";
|
||||||
import { BaseResponse } from "../../../models/response/base.response";
|
import { BaseResponse } from "../../../models/response/base.response";
|
||||||
import { Region } from "../../abstractions/environment.service";
|
import { Region } from "../../abstractions/environment.service";
|
||||||
|
import { ServerSettings } from "../domain/server-settings";
|
||||||
|
|
||||||
export class ServerConfigResponse extends BaseResponse {
|
export class ServerConfigResponse extends BaseResponse {
|
||||||
version: string;
|
version: string;
|
||||||
@ -8,6 +9,7 @@ export class ServerConfigResponse extends BaseResponse {
|
|||||||
server: ThirdPartyServerConfigResponse;
|
server: ThirdPartyServerConfigResponse;
|
||||||
environment: EnvironmentServerConfigResponse;
|
environment: EnvironmentServerConfigResponse;
|
||||||
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
|
featureStates: { [key: string]: AllowedFeatureFlagTypes } = {};
|
||||||
|
settings: ServerSettings;
|
||||||
|
|
||||||
constructor(response: any) {
|
constructor(response: any) {
|
||||||
super(response);
|
super(response);
|
||||||
@ -21,6 +23,7 @@ export class ServerConfigResponse extends BaseResponse {
|
|||||||
this.server = new ThirdPartyServerConfigResponse(this.getResponseProperty("Server"));
|
this.server = new ThirdPartyServerConfigResponse(this.getResponseProperty("Server"));
|
||||||
this.environment = new EnvironmentServerConfigResponse(this.getResponseProperty("Environment"));
|
this.environment = new EnvironmentServerConfigResponse(this.getResponseProperty("Environment"));
|
||||||
this.featureStates = this.getResponseProperty("FeatureStates");
|
this.featureStates = this.getResponseProperty("FeatureStates");
|
||||||
|
this.settings = new ServerSettings(this.getResponseProperty("Settings"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import { Environment, EnvironmentService, Region } from "../../abstractions/envi
|
|||||||
import { LogService } from "../../abstractions/log.service";
|
import { LogService } from "../../abstractions/log.service";
|
||||||
import { devFlagEnabled, devFlagValue } from "../../misc/flags";
|
import { devFlagEnabled, devFlagValue } from "../../misc/flags";
|
||||||
import { ServerConfigData } from "../../models/data/server-config.data";
|
import { ServerConfigData } from "../../models/data/server-config.data";
|
||||||
|
import { ServerSettings } from "../../models/domain/server-settings";
|
||||||
import { CONFIG_DISK, KeyDefinition, StateProvider, UserKeyDefinition } from "../../state";
|
import { CONFIG_DISK, KeyDefinition, StateProvider, UserKeyDefinition } from "../../state";
|
||||||
|
|
||||||
export const RETRIEVAL_INTERVAL = devFlagEnabled("configRetrievalIntervalMs")
|
export const RETRIEVAL_INTERVAL = devFlagEnabled("configRetrievalIntervalMs")
|
||||||
@ -57,6 +58,8 @@ export class DefaultConfigService implements ConfigService {
|
|||||||
|
|
||||||
serverConfig$: Observable<ServerConfig>;
|
serverConfig$: Observable<ServerConfig>;
|
||||||
|
|
||||||
|
serverSettings$: Observable<ServerSettings>;
|
||||||
|
|
||||||
cloudRegion$: Observable<Region>;
|
cloudRegion$: Observable<Region>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -111,6 +114,10 @@ export class DefaultConfigService implements ConfigService {
|
|||||||
this.cloudRegion$ = this.serverConfig$.pipe(
|
this.cloudRegion$ = this.serverConfig$.pipe(
|
||||||
map((config) => config?.environment?.cloudRegion ?? Region.US),
|
map((config) => config?.environment?.cloudRegion ?? Region.US),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.serverSettings$ = this.serverConfig$.pipe(
|
||||||
|
map((config) => config?.settings ?? new ServerSettings()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeatureFlag$<Flag extends FeatureFlag>(key: Flag) {
|
getFeatureFlag$<Flag extends FeatureFlag>(key: Flag) {
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -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<ServerSettings> {
|
||||||
|
return this.configService.serverSettings$;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isUserRegistrationDisabled$(): Observable<boolean> {
|
||||||
|
return this.getSettings$().pipe(
|
||||||
|
map((settings: ServerSettings) => settings.disableUserRegistration),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user