Submodule jslib contains modified content
diff --git a/jslib/angular/src/components/register.component.ts b/jslib/angular/src/components/register.component.ts
index 53ec3c8..7b49db1 100644
--- a/jslib/angular/src/components/register.component.ts
+++ b/jslib/angular/src/components/register.component.ts
@@ -24,7 +24,7 @@ export class RegisterComponent {
formPromise: Promise;
masterPasswordScore: number;
referenceData: ReferenceEventRequest;
- showTerms = true;
+ showTerms = false;
acceptPolicies: boolean = false;
protected successRoute = 'login';
@@ -35,7 +35,7 @@ export class RegisterComponent {
protected apiService: ApiService, protected stateService: StateService,
protected platformUtilsService: PlatformUtilsService,
protected passwordGenerationService: PasswordGenerationService) {
- this.showTerms = !platformUtilsService.isSelfHost();
+ this.showTerms = false;
}
get masterPasswordScoreWidth() {
@@ -69,6 +69,12 @@ export class RegisterComponent {
}
async submit() {
+ if (typeof crypto.subtle === 'undefined') {
+ this.platformUtilsService.showToast('error', "This browser requires HTTPS to use the web vault",
+ "Check the Vaultwarden wiki for details on how to enable it");
+ return;
+ }
+
if (!this.acceptPolicies && this.showTerms) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('acceptPoliciesError'));
diff --git a/jslib/angular/src/components/sso.component.ts b/jslib/angular/src/components/sso.component.ts
index d4512a1..ad57f69 100644
--- a/jslib/angular/src/components/sso.component.ts
+++ b/jslib/angular/src/components/sso.component.ts
@@ -19,6 +19,8 @@ import { Utils } from 'jslib-common/misc/utils';
import { AuthResult } from 'jslib-common/models/domain/authResult';
+import { switchMap } from 'rxjs/operators';
+
@Directive()
export class SsoComponent {
identifier: string;
@@ -48,13 +50,19 @@ export class SsoComponent {
async ngOnInit() {
const queryParamsSub = this.route.queryParams.subscribe(async qParams => {
- if (qParams.code != null && qParams.state != null) {
+ // I have no idea why the qParams is empty here - I've hacked in an alternative very messily, but it works.
+ const workingParams = (new URL(window.location.href)).searchParams;
+ const workingSwap = {
+ code: workingParams.get('code'),
+ state: workingParams.get('state'),
+ };
+ if (workingSwap.code != null && workingSwap.state != null) {
const codeVerifier = await this.storageService.get(ConstantsService.ssoCodeVerifierKey);
const state = await this.storageService.get(ConstantsService.ssoStateKey);
await this.storageService.remove(ConstantsService.ssoCodeVerifierKey);
await this.storageService.remove(ConstantsService.ssoStateKey);
- if (qParams.code != null && codeVerifier != null && state != null && this.checkState(state, qParams.state)) {
- await this.logIn(qParams.code, codeVerifier, this.getOrgIdentiferFromState(qParams.state));
+ if (workingSwap.code != null && codeVerifier != null && state != null && this.checkState(state, workingSwap.state)) {
+ await this.logIn(workingSwap.code, codeVerifier, this.getOrgIdentiferFromState(workingSwap.state));
}
} else if (qParams.clientId != null && qParams.redirectUri != null && qParams.state != null &&
qParams.codeChallenge != null) {
@@ -122,7 +130,7 @@ export class SsoComponent {
let authorizeUrl = this.apiService.identityBaseUrl + '/connect/authorize?' +
'client_id=' + this.clientId + '&redirect_uri=' + encodeURIComponent(this.redirectUri) + '&' +
'response_type=code&scope=api offline_access&' +
- 'state=' + state + '&code_challenge=' + codeChallenge + '&' +
+ 'state=' + encodeURIComponent(state) + '&code_challenge=' + codeChallenge + '&' +
'code_challenge_method=S256&response_mode=query&' +
'domain_hint=' + encodeURIComponent(this.identifier);
@@ -137,7 +145,7 @@ export class SsoComponent {
private async logIn(code: string, codeVerifier: string, orgIdFromState: string) {
this.loggingIn = true;
try {
- this.formPromise = this.authService.logInSso(code, codeVerifier, this.redirectUri);
+ this.formPromise = this.authService.logInSso(code, codeVerifier, this.redirectUri, orgIdFromState);
const response = await this.formPromise;
if (response.twoFactor) {
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
diff --git a/jslib/common/src/abstractions/api.service.ts b/jslib/common/src/abstractions/api.service.ts
index 67131df..e75a874 100644
--- a/jslib/common/src/abstractions/api.service.ts
+++ b/jslib/common/src/abstractions/api.service.ts
@@ -33,6 +33,7 @@ import { KeysRequest } from '../models/request/keysRequest';
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
import { OrganizationKeysRequest } from '../models/request/organizationKeysRequest';
+import { OrganizationSsoUpdateRequest } from '../models/request/organizationSsoUpdateRequest';
import { OrganizationTaxInfoUpdateRequest } from '../models/request/organizationTaxInfoUpdateRequest';
import { OrganizationUpdateRequest } from '../models/request/organizationUpdateRequest';
import { OrganizationUpgradeRequest } from '../models/request/organizationUpgradeRequest';
@@ -360,6 +361,7 @@ export abstract class ApiService {
getOrganizationTaxInfo: (id: string) => Promise;
postOrganization: (request: OrganizationCreateRequest) => Promise;
putOrganization: (id: string, request: OrganizationUpdateRequest) => Promise;
+ putOrganizationSso: (id: string, request: OrganizationSsoUpdateRequest) => Promise;
putOrganizationTaxInfo: (id: string, request: OrganizationTaxInfoUpdateRequest) => Promise;
postLeaveOrganization: (id: string) => Promise;
postOrganizationLicense: (data: FormData) => Promise;
diff --git a/jslib/common/src/abstractions/auth.service.ts b/jslib/common/src/abstractions/auth.service.ts
index ac7ef04..5b1b774 100644
--- a/jslib/common/src/abstractions/auth.service.ts
+++ b/jslib/common/src/abstractions/auth.service.ts
@@ -15,7 +15,7 @@ export abstract class AuthService {
selectedTwoFactorProviderType: TwoFactorProviderType;
logIn: (email: string, masterPassword: string) => Promise;
- logInSso: (code: string, codeVerifier: string, redirectUrl: string) => Promise;
+ logInSso: (code: string, codeVerifier: string, redirectUrl: string, orgIdentifier: string) => Promise;
logInApiKey: (clientId: string, clientSecret: string) => Promise;
logInTwoFactor: (twoFactorProvider: TwoFactorProviderType, twoFactorToken: string,
remember?: boolean) => Promise;
diff --git a/jslib/common/src/models/request/organizationSsoUpdateRequest.ts b/jslib/common/src/models/request/organizationSsoUpdateRequest.ts
new file mode 100644
index 0000000..7075aec
--- /dev/null
+++ b/jslib/common/src/models/request/organizationSsoUpdateRequest.ts
@@ -0,0 +1,8 @@
+export class OrganizationSsoUpdateRequest {
+ useSso: boolean;
+ callbackPath: string;
+ signedOutCallbackPath: string;
+ authority: string;
+ clientId: string;
+ clientSecret: string;
+}
diff --git a/jslib/common/src/models/request/tokenRequest.ts b/jslib/common/src/models/request/tokenRequest.ts
index 7578012..964364f 100644
--- a/jslib/common/src/models/request/tokenRequest.ts
+++ b/jslib/common/src/models/request/tokenRequest.ts
@@ -14,9 +14,10 @@ export class TokenRequest {
provider: TwoFactorProviderType;
remember: boolean;
device?: DeviceRequest;
+ orgIdentifier?: string;
constructor(credentials: string[], codes: string[], clientIdClientSecret: string[], provider: TwoFactorProviderType,
- token: string, remember: boolean, device?: DeviceRequest) {
+ token: string, remember: boolean, device?: DeviceRequest, orgIdentifier?: string) {
if (credentials != null && credentials.length > 1) {
this.email = credentials[0];
this.masterPasswordHash = credentials[1];
@@ -28,6 +29,9 @@ export class TokenRequest {
this.clientId = clientIdClientSecret[0];
this.clientSecret = clientIdClientSecret[1];
}
+ if (orgIdentifier && orgIdentifier !== '') {
+ this.orgIdentifier = orgIdentifier;
+ }
this.token = token;
this.provider = provider;
this.remember = remember;
@@ -53,6 +57,7 @@ export class TokenRequest {
obj.code = this.code;
obj.code_verifier = this.codeVerifier;
obj.redirect_uri = this.redirectUri;
+ obj.org_identifier = this.orgIdentifier;
} else {
throw new Error('must provide credentials or codes');
}
diff --git a/jslib/common/src/models/response/organizationResponse.ts b/jslib/common/src/models/response/organizationResponse.ts
index 21d8d43..896b7a6 100644
--- a/jslib/common/src/models/response/organizationResponse.ts
+++ b/jslib/common/src/models/response/organizationResponse.ts
@@ -27,6 +27,12 @@ export class OrganizationResponse extends BaseResponse {
useApi: boolean;
useResetPassword: boolean;
hasPublicAndPrivateKeys: boolean;
+ useSso: boolean;
+ callbackPath: string;
+ signedOutCallbackPath: string;
+ authority: string;
+ clientId: string;
+ clientSecret: string;
constructor(response: any) {
super(response);
@@ -54,5 +60,11 @@ export class OrganizationResponse extends BaseResponse {
this.useApi = this.getResponseProperty('UseApi');
this.useResetPassword = this.getResponseProperty('UseResetPassword');
this.hasPublicAndPrivateKeys = this.getResponseProperty('HasPublicAndPrivateKeys');
+ this.useSso = this.getResponseProperty('UseSso');
+ this.callbackPath = this.getResponseProperty('CallbackPath');
+ this.signedOutCallbackPath = this.getResponseProperty('SignedOutCallbackPath');
+ this.authority = this.getResponseProperty('Authority');
+ this.clientId = this.getResponseProperty('ClientId');
+ this.clientSecret = this.getResponseProperty('ClientSecret');
}
}
diff --git a/jslib/common/src/models/response/organizationSsoResponse.ts b/jslib/common/src/models/response/organizationSsoResponse.ts
new file mode 100644
index 0000000..896b7a6
--- /dev/null
+++ b/jslib/common/src/models/response/organizationSsoResponse.ts
@@ -0,0 +1,70 @@
+import { BaseResponse } from './baseResponse';
+import { PlanResponse } from './planResponse';
+
+import { PlanType } from '../../enums/planType';
+
+export class OrganizationResponse extends BaseResponse {
+ id: string;
+ identifier: string;
+ name: string;
+ businessName: string;
+ businessAddress1: string;
+ businessAddress2: string;
+ businessAddress3: string;
+ businessCountry: string;
+ businessTaxNumber: string;
+ billingEmail: string;
+ plan: PlanResponse;
+ planType: PlanType;
+ seats: number;
+ maxCollections: number;
+ maxStorageGb: number;
+ useGroups: boolean;
+ useDirectory: boolean;
+ useEvents: boolean;
+ useTotp: boolean;
+ use2fa: boolean;
+ useApi: boolean;
+ useResetPassword: boolean;
+ hasPublicAndPrivateKeys: boolean;
+ useSso: boolean;
+ callbackPath: string;
+ signedOutCallbackPath: string;
+ authority: string;
+ clientId: string;
+ clientSecret: string;
+
+ constructor(response: any) {
+ super(response);
+ this.id = this.getResponseProperty('Id');
+ this.identifier = this.getResponseProperty('Identifier');
+ this.name = this.getResponseProperty('Name');
+ this.businessName = this.getResponseProperty('BusinessName');
+ this.businessAddress1 = this.getResponseProperty('BusinessAddress1');
+ this.businessAddress2 = this.getResponseProperty('BusinessAddress2');
+ this.businessAddress3 = this.getResponseProperty('BusinessAddress3');
+ this.businessCountry = this.getResponseProperty('BusinessCountry');
+ this.businessTaxNumber = this.getResponseProperty('BusinessTaxNumber');
+ this.billingEmail = this.getResponseProperty('BillingEmail');
+ const plan = this.getResponseProperty('Plan');
+ this.plan = plan == null ? null : new PlanResponse(plan);
+ this.planType = this.getResponseProperty('PlanType');
+ this.seats = this.getResponseProperty('Seats');
+ this.maxCollections = this.getResponseProperty('MaxCollections');
+ this.maxStorageGb = this.getResponseProperty('MaxStorageGb');
+ this.useGroups = this.getResponseProperty('UseGroups');
+ this.useDirectory = this.getResponseProperty('UseDirectory');
+ this.useEvents = this.getResponseProperty('UseEvents');
+ this.useTotp = this.getResponseProperty('UseTotp');
+ this.use2fa = this.getResponseProperty('Use2fa');
+ this.useApi = this.getResponseProperty('UseApi');
+ this.useResetPassword = this.getResponseProperty('UseResetPassword');
+ this.hasPublicAndPrivateKeys = this.getResponseProperty('HasPublicAndPrivateKeys');
+ this.useSso = this.getResponseProperty('UseSso');
+ this.callbackPath = this.getResponseProperty('CallbackPath');
+ this.signedOutCallbackPath = this.getResponseProperty('SignedOutCallbackPath');
+ this.authority = this.getResponseProperty('Authority');
+ this.clientId = this.getResponseProperty('ClientId');
+ this.clientSecret = this.getResponseProperty('ClientSecret');
+ }
+}
diff --git a/jslib/common/src/services/api.service.ts b/jslib/common/src/services/api.service.ts
index 51c1c14..1a5b088 100644
--- a/jslib/common/src/services/api.service.ts
+++ b/jslib/common/src/services/api.service.ts
@@ -37,6 +37,7 @@ import { KeysRequest } from '../models/request/keysRequest';
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
import { OrganizationKeysRequest } from '../models/request/organizationKeysRequest';
+import { OrganizationSsoUpdateRequest } from '../models/request/organizationSsoUpdateRequest';
import { OrganizationTaxInfoUpdateRequest } from '../models/request/organizationTaxInfoUpdateRequest';
import { OrganizationUpdateRequest } from '../models/request/organizationUpdateRequest';
import { OrganizationUpgradeRequest } from '../models/request/organizationUpgradeRequest';
@@ -1158,6 +1159,11 @@ export class ApiService implements ApiServiceAbstraction {
return new OrganizationResponse(r);
}
+ async putOrganizationSso(id: string, request: OrganizationSsoUpdateRequest): Promise {
+ const r = await this.send('PUT', '/organizations/' + id + '/sso', request, true, false);
+ return new OrganizationResponse(r);
+ }
+
async putOrganizationTaxInfo(id: string, request: OrganizationTaxInfoUpdateRequest): Promise {
return this.send('PUT', '/organizations/' + id + '/tax', request, true, false);
}
diff --git a/jslib/common/src/services/auth.service.ts b/jslib/common/src/services/auth.service.ts
index 6536a94..6f4899c 100644
--- a/jslib/common/src/services/auth.service.ts
+++ b/jslib/common/src/services/auth.service.ts
@@ -130,10 +130,10 @@ export class AuthService implements AuthServiceAbstraction {
key, null, null, null);
}
- async logInSso(code: string, codeVerifier: string, redirectUrl: string): Promise {
+ async logInSso(code: string, codeVerifier: string, redirectUrl: string, orgIdentifier: string): Promise {
this.selectedTwoFactorProviderType = null;
return await this.logInHelper(null, null, null, code, codeVerifier, redirectUrl, null, null,
- null, null, null, null);
+ null, null, null, null, orgIdentifier);
}
async logInApiKey(clientId: string, clientSecret: string): Promise {
@@ -272,7 +272,7 @@ export class AuthService implements AuthServiceAbstraction {
private async logInHelper(email: string, hashedPassword: string, localHashedPassword: string, code: string,
codeVerifier: string, redirectUrl: string, clientId: string, clientSecret: string, key: SymmetricCryptoKey,
- twoFactorProvider?: TwoFactorProviderType, twoFactorToken?: string, remember?: boolean): Promise {
+ twoFactorProvider?: TwoFactorProviderType, twoFactorToken?: string, remember?: boolean, orgIdentifier?: string): Promise {
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
const appId = await this.appIdService.getAppId();
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
@@ -300,13 +300,13 @@ export class AuthService implements AuthServiceAbstraction {
let request: TokenRequest;
if (twoFactorToken != null && twoFactorProvider != null) {
request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, twoFactorProvider,
- twoFactorToken, remember, deviceRequest);
+ twoFactorToken, remember, deviceRequest, orgIdentifier);
} else if (storedTwoFactorToken != null) {
request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, TwoFactorProviderType.Remember,
- storedTwoFactorToken, false, deviceRequest);
+ storedTwoFactorToken, false, deviceRequest, orgIdentifier);
} else {
request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, null,
- null, false, deviceRequest);
+ null, false, deviceRequest, orgIdentifier);
}
const response = await this.apiService.postIdentityToken(request);
diff --git a/src/404.html b/src/404.html
index eba36375..cb8883ec 100644
--- a/src/404.html
+++ b/src/404.html
@@ -41,10 +41,10 @@
You can return to the web vault, check our status page
- or contact us.
+ or contact us.