mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-21 16:18:28 +01:00
fixes (#7145)
This commit is contained in:
parent
014281cb93
commit
e359aef979
@ -39,12 +39,19 @@ export class Client {
|
||||
async openVault(
|
||||
username: string,
|
||||
password: string,
|
||||
fragmentId: string,
|
||||
clientInfo: ClientInfo,
|
||||
ui: Ui,
|
||||
options: ParserOptions,
|
||||
): Promise<Account[]> {
|
||||
const lowercaseUsername = username.toLowerCase();
|
||||
const [session, rest] = await this.login(lowercaseUsername, password, clientInfo, ui);
|
||||
const [session, rest] = await this.login(
|
||||
lowercaseUsername,
|
||||
password,
|
||||
fragmentId,
|
||||
clientInfo,
|
||||
ui,
|
||||
);
|
||||
try {
|
||||
const blob = await this.downloadVault(session, rest);
|
||||
const key = await this.cryptoUtils.deriveKey(
|
||||
@ -111,6 +118,7 @@ export class Client {
|
||||
private async login(
|
||||
username: string,
|
||||
password: string,
|
||||
fragmentId: string,
|
||||
clientInfo: ClientInfo,
|
||||
ui: Ui,
|
||||
): Promise<[Session, RestClient]> {
|
||||
@ -142,6 +150,7 @@ export class Client {
|
||||
response = await this.performSingleLoginRequest(
|
||||
username,
|
||||
password,
|
||||
fragmentId,
|
||||
keyIterationCount,
|
||||
new Map<string, any>(),
|
||||
clientInfo,
|
||||
@ -191,6 +200,7 @@ export class Client {
|
||||
session = await this.loginWithOtp(
|
||||
username,
|
||||
password,
|
||||
fragmentId,
|
||||
keyIterationCount,
|
||||
optMethod,
|
||||
clientInfo,
|
||||
@ -203,6 +213,7 @@ export class Client {
|
||||
session = await this.loginWithOob(
|
||||
username,
|
||||
password,
|
||||
fragmentId,
|
||||
keyIterationCount,
|
||||
this.getAllErrorAttributes(response),
|
||||
clientInfo,
|
||||
@ -223,6 +234,7 @@ export class Client {
|
||||
private async loginWithOtp(
|
||||
username: string,
|
||||
password: string,
|
||||
fragmentId: string,
|
||||
keyIterationCount: number,
|
||||
method: OtpMethod,
|
||||
clientInfo: ClientInfo,
|
||||
@ -251,6 +263,7 @@ export class Client {
|
||||
const response = await this.performSingleLoginRequest(
|
||||
username,
|
||||
password,
|
||||
fragmentId,
|
||||
keyIterationCount,
|
||||
new Map<string, string>([["otp", passcode.passcode]]),
|
||||
clientInfo,
|
||||
@ -270,6 +283,7 @@ export class Client {
|
||||
private async loginWithOob(
|
||||
username: string,
|
||||
password: string,
|
||||
fragmentId: string,
|
||||
keyIterationCount: number,
|
||||
parameters: Map<string, string>,
|
||||
clientInfo: ClientInfo,
|
||||
@ -282,6 +296,7 @@ export class Client {
|
||||
const response = await this.performSingleLoginRequest(
|
||||
username,
|
||||
password,
|
||||
fragmentId,
|
||||
keyIterationCount,
|
||||
extraParameters,
|
||||
clientInfo,
|
||||
@ -494,6 +509,7 @@ export class Client {
|
||||
private async performSingleLoginRequest(
|
||||
username: string,
|
||||
password: string,
|
||||
fragmentId: string,
|
||||
keyIterationCount: number,
|
||||
extraParameters: Map<string, any>,
|
||||
clientInfo: ClientInfo,
|
||||
@ -513,6 +529,10 @@ export class Client {
|
||||
// TODO: Test against the real server if it's ok to send this every time!
|
||||
["trustlabel", clientInfo.description],
|
||||
]);
|
||||
if (fragmentId != null) {
|
||||
parameters.set("alpfragmentid", fragmentId);
|
||||
parameters.set("calculatedfragmentid", fragmentId);
|
||||
}
|
||||
for (const [key, value] of extraParameters) {
|
||||
parameters.set(key, value);
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ export class Parser {
|
||||
|
||||
// 3: url
|
||||
let url = Utils.fromBufferToUtf8(
|
||||
Utils.fromHexToArray(Utils.fromBufferToUtf8(this.readItem(reader))),
|
||||
this.decodeHexLoose(Utils.fromBufferToUtf8(this.readItem(reader))),
|
||||
);
|
||||
|
||||
// Ignore "group" accounts. They have no credentials.
|
||||
@ -354,4 +354,9 @@ export class Parser {
|
||||
private readPayload(reader: BinaryReader, size: number): Uint8Array {
|
||||
return reader.readBytes(size);
|
||||
}
|
||||
|
||||
private decodeHexLoose(s: string): Uint8Array {
|
||||
// This is a forgiving version that pads the input with a '0' when the length is odd
|
||||
return Utils.fromHexToArray(s.length % 2 == 0 ? s : "0" + s);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,14 @@ export class Vault {
|
||||
ui: Ui,
|
||||
parserOptions: ParserOptions = ParserOptions.default,
|
||||
): Promise<void> {
|
||||
this.accounts = await this.client.openVault(username, password, clientInfo, ui, parserOptions);
|
||||
this.accounts = await this.client.openVault(
|
||||
username,
|
||||
password,
|
||||
null,
|
||||
clientInfo,
|
||||
ui,
|
||||
parserOptions,
|
||||
);
|
||||
}
|
||||
|
||||
async openFederated(
|
||||
@ -53,13 +60,20 @@ export class Vault {
|
||||
throw new Error("Federated user context is not set.");
|
||||
}
|
||||
const k1 = await this.getK1(federatedUser);
|
||||
const k2 = await this.getK2(federatedUser);
|
||||
const [k2, fragmentId] = await this.getK2FragmentId(federatedUser);
|
||||
const hiddenPasswordArr = await this.cryptoFunctionService.hash(
|
||||
this.cryptoUtils.ExclusiveOr(k1, k2),
|
||||
"sha256",
|
||||
);
|
||||
const hiddenPassword = Utils.fromBufferToB64(hiddenPasswordArr);
|
||||
await this.open(federatedUser.username, hiddenPassword, clientInfo, ui, parserOptions);
|
||||
this.accounts = await this.client.openVault(
|
||||
federatedUser.username,
|
||||
hiddenPassword,
|
||||
fragmentId,
|
||||
clientInfo,
|
||||
ui,
|
||||
parserOptions,
|
||||
);
|
||||
}
|
||||
|
||||
async setUserTypeContext(username: string) {
|
||||
@ -80,6 +94,18 @@ export class Vault {
|
||||
this.userType.pkceEnabled = json.PkceEnabled;
|
||||
this.userType.provider = json.Provider;
|
||||
this.userType.type = json.type;
|
||||
|
||||
if (this.userType.provider === IdpProvider.Azure) {
|
||||
// Sometimes customers have malformed OIDC authority URLs. Try to fix them.
|
||||
const appQueryIndex = this.userType.openIDConnectAuthority.indexOf("?app");
|
||||
if (appQueryIndex > -1) {
|
||||
this.userType.openIDConnectAuthority = this.userType.openIDConnectAuthority.substring(
|
||||
0,
|
||||
appQueryIndex,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
throw new Error("Cannot determine LastPass user type.");
|
||||
@ -194,7 +220,9 @@ export class Vault {
|
||||
return null;
|
||||
}
|
||||
|
||||
private async getK2(federatedUser: FederatedUserContext): Promise<Uint8Array> {
|
||||
private async getK2FragmentId(
|
||||
federatedUser: FederatedUserContext,
|
||||
): Promise<[Uint8Array, string]> {
|
||||
if (this.userType == null) {
|
||||
throw new Error("User type is not set.");
|
||||
}
|
||||
@ -212,10 +240,11 @@ export class Vault {
|
||||
if (response.status === HttpStatusCode.Ok) {
|
||||
const json = await response.json();
|
||||
const k2 = json?.k2 as string;
|
||||
if (k2 != null) {
|
||||
return Utils.fromB64ToArray(k2);
|
||||
const fragmentId = json?.fragment_id as string;
|
||||
if (k2 != null && fragmentId != null) {
|
||||
return [Utils.fromB64ToArray(k2), fragmentId];
|
||||
}
|
||||
}
|
||||
throw new Error("Cannot get k2.");
|
||||
throw new Error("Cannot get k2 and/or fragment ID.");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user