mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-02 18:17:46 +01:00
fixes (#7145)
This commit is contained in:
parent
014281cb93
commit
e359aef979
@ -39,12 +39,19 @@ export class Client {
|
|||||||
async openVault(
|
async openVault(
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
|
fragmentId: string,
|
||||||
clientInfo: ClientInfo,
|
clientInfo: ClientInfo,
|
||||||
ui: Ui,
|
ui: Ui,
|
||||||
options: ParserOptions,
|
options: ParserOptions,
|
||||||
): Promise<Account[]> {
|
): Promise<Account[]> {
|
||||||
const lowercaseUsername = username.toLowerCase();
|
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 {
|
try {
|
||||||
const blob = await this.downloadVault(session, rest);
|
const blob = await this.downloadVault(session, rest);
|
||||||
const key = await this.cryptoUtils.deriveKey(
|
const key = await this.cryptoUtils.deriveKey(
|
||||||
@ -111,6 +118,7 @@ export class Client {
|
|||||||
private async login(
|
private async login(
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
|
fragmentId: string,
|
||||||
clientInfo: ClientInfo,
|
clientInfo: ClientInfo,
|
||||||
ui: Ui,
|
ui: Ui,
|
||||||
): Promise<[Session, RestClient]> {
|
): Promise<[Session, RestClient]> {
|
||||||
@ -142,6 +150,7 @@ export class Client {
|
|||||||
response = await this.performSingleLoginRequest(
|
response = await this.performSingleLoginRequest(
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
fragmentId,
|
||||||
keyIterationCount,
|
keyIterationCount,
|
||||||
new Map<string, any>(),
|
new Map<string, any>(),
|
||||||
clientInfo,
|
clientInfo,
|
||||||
@ -191,6 +200,7 @@ export class Client {
|
|||||||
session = await this.loginWithOtp(
|
session = await this.loginWithOtp(
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
fragmentId,
|
||||||
keyIterationCount,
|
keyIterationCount,
|
||||||
optMethod,
|
optMethod,
|
||||||
clientInfo,
|
clientInfo,
|
||||||
@ -203,6 +213,7 @@ export class Client {
|
|||||||
session = await this.loginWithOob(
|
session = await this.loginWithOob(
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
fragmentId,
|
||||||
keyIterationCount,
|
keyIterationCount,
|
||||||
this.getAllErrorAttributes(response),
|
this.getAllErrorAttributes(response),
|
||||||
clientInfo,
|
clientInfo,
|
||||||
@ -223,6 +234,7 @@ export class Client {
|
|||||||
private async loginWithOtp(
|
private async loginWithOtp(
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
|
fragmentId: string,
|
||||||
keyIterationCount: number,
|
keyIterationCount: number,
|
||||||
method: OtpMethod,
|
method: OtpMethod,
|
||||||
clientInfo: ClientInfo,
|
clientInfo: ClientInfo,
|
||||||
@ -251,6 +263,7 @@ export class Client {
|
|||||||
const response = await this.performSingleLoginRequest(
|
const response = await this.performSingleLoginRequest(
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
fragmentId,
|
||||||
keyIterationCount,
|
keyIterationCount,
|
||||||
new Map<string, string>([["otp", passcode.passcode]]),
|
new Map<string, string>([["otp", passcode.passcode]]),
|
||||||
clientInfo,
|
clientInfo,
|
||||||
@ -270,6 +283,7 @@ export class Client {
|
|||||||
private async loginWithOob(
|
private async loginWithOob(
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
|
fragmentId: string,
|
||||||
keyIterationCount: number,
|
keyIterationCount: number,
|
||||||
parameters: Map<string, string>,
|
parameters: Map<string, string>,
|
||||||
clientInfo: ClientInfo,
|
clientInfo: ClientInfo,
|
||||||
@ -282,6 +296,7 @@ export class Client {
|
|||||||
const response = await this.performSingleLoginRequest(
|
const response = await this.performSingleLoginRequest(
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
fragmentId,
|
||||||
keyIterationCount,
|
keyIterationCount,
|
||||||
extraParameters,
|
extraParameters,
|
||||||
clientInfo,
|
clientInfo,
|
||||||
@ -494,6 +509,7 @@ export class Client {
|
|||||||
private async performSingleLoginRequest(
|
private async performSingleLoginRequest(
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
|
fragmentId: string,
|
||||||
keyIterationCount: number,
|
keyIterationCount: number,
|
||||||
extraParameters: Map<string, any>,
|
extraParameters: Map<string, any>,
|
||||||
clientInfo: ClientInfo,
|
clientInfo: ClientInfo,
|
||||||
@ -513,6 +529,10 @@ export class Client {
|
|||||||
// TODO: Test against the real server if it's ok to send this every time!
|
// TODO: Test against the real server if it's ok to send this every time!
|
||||||
["trustlabel", clientInfo.description],
|
["trustlabel", clientInfo.description],
|
||||||
]);
|
]);
|
||||||
|
if (fragmentId != null) {
|
||||||
|
parameters.set("alpfragmentid", fragmentId);
|
||||||
|
parameters.set("calculatedfragmentid", fragmentId);
|
||||||
|
}
|
||||||
for (const [key, value] of extraParameters) {
|
for (const [key, value] of extraParameters) {
|
||||||
parameters.set(key, value);
|
parameters.set(key, value);
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ export class Parser {
|
|||||||
|
|
||||||
// 3: url
|
// 3: url
|
||||||
let url = Utils.fromBufferToUtf8(
|
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.
|
// Ignore "group" accounts. They have no credentials.
|
||||||
@ -354,4 +354,9 @@ export class Parser {
|
|||||||
private readPayload(reader: BinaryReader, size: number): Uint8Array {
|
private readPayload(reader: BinaryReader, size: number): Uint8Array {
|
||||||
return reader.readBytes(size);
|
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,
|
ui: Ui,
|
||||||
parserOptions: ParserOptions = ParserOptions.default,
|
parserOptions: ParserOptions = ParserOptions.default,
|
||||||
): Promise<void> {
|
): 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(
|
async openFederated(
|
||||||
@ -53,13 +60,20 @@ export class Vault {
|
|||||||
throw new Error("Federated user context is not set.");
|
throw new Error("Federated user context is not set.");
|
||||||
}
|
}
|
||||||
const k1 = await this.getK1(federatedUser);
|
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(
|
const hiddenPasswordArr = await this.cryptoFunctionService.hash(
|
||||||
this.cryptoUtils.ExclusiveOr(k1, k2),
|
this.cryptoUtils.ExclusiveOr(k1, k2),
|
||||||
"sha256",
|
"sha256",
|
||||||
);
|
);
|
||||||
const hiddenPassword = Utils.fromBufferToB64(hiddenPasswordArr);
|
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) {
|
async setUserTypeContext(username: string) {
|
||||||
@ -80,6 +94,18 @@ export class Vault {
|
|||||||
this.userType.pkceEnabled = json.PkceEnabled;
|
this.userType.pkceEnabled = json.PkceEnabled;
|
||||||
this.userType.provider = json.Provider;
|
this.userType.provider = json.Provider;
|
||||||
this.userType.type = json.type;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
throw new Error("Cannot determine LastPass user type.");
|
throw new Error("Cannot determine LastPass user type.");
|
||||||
@ -194,7 +220,9 @@ export class Vault {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getK2(federatedUser: FederatedUserContext): Promise<Uint8Array> {
|
private async getK2FragmentId(
|
||||||
|
federatedUser: FederatedUserContext,
|
||||||
|
): Promise<[Uint8Array, string]> {
|
||||||
if (this.userType == null) {
|
if (this.userType == null) {
|
||||||
throw new Error("User type is not set.");
|
throw new Error("User type is not set.");
|
||||||
}
|
}
|
||||||
@ -212,10 +240,11 @@ export class Vault {
|
|||||||
if (response.status === HttpStatusCode.Ok) {
|
if (response.status === HttpStatusCode.Ok) {
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
const k2 = json?.k2 as string;
|
const k2 = json?.k2 as string;
|
||||||
if (k2 != null) {
|
const fragmentId = json?.fragment_id as string;
|
||||||
return Utils.fromB64ToArray(k2);
|
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