mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 00:33:44 +00:00
Merge branch 'main' into PM-26250-Explore-options-to-enable-direct-importer-for-mac-app-store-build
This commit is contained in:
6
.github/workflows/build-desktop.yml
vendored
6
.github/workflows/build-desktop.yml
vendored
@@ -1019,7 +1019,7 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
||||||
with:
|
with:
|
||||||
python-version: '3.14'
|
python-version: '3.14.2'
|
||||||
|
|
||||||
- name: Set up Node-gyp
|
- name: Set up Node-gyp
|
||||||
run: python -m pip install setuptools
|
run: python -m pip install setuptools
|
||||||
@@ -1257,7 +1257,7 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
||||||
with:
|
with:
|
||||||
python-version: '3.14'
|
python-version: '3.14.2'
|
||||||
|
|
||||||
- name: Set up Node-gyp
|
- name: Set up Node-gyp
|
||||||
run: python -m pip install setuptools
|
run: python -m pip install setuptools
|
||||||
@@ -1530,7 +1530,7 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
||||||
with:
|
with:
|
||||||
python-version: '3.14'
|
python-version: '3.14.2'
|
||||||
|
|
||||||
- name: Set up Node-gyp
|
- name: Set up Node-gyp
|
||||||
run: python -m pip install setuptools
|
run: python -m pip install setuptools
|
||||||
|
|||||||
@@ -5934,5 +5934,8 @@
|
|||||||
},
|
},
|
||||||
"sessionTimeoutSettingsSetUnlockMethodToChangeTimeoutAction": {
|
"sessionTimeoutSettingsSetUnlockMethodToChangeTimeoutAction": {
|
||||||
"message": "Set an unlock method to change your timeout action"
|
"message": "Set an unlock method to change your timeout action"
|
||||||
|
},
|
||||||
|
"upgrade": {
|
||||||
|
"message": "Upgrade"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<button bitButton size="small" [bitMenuTriggerFor]="itemOptions" buttonType="primary" type="button">
|
<button bitButton [bitMenuTriggerFor]="itemOptions" buttonType="primary" type="button">
|
||||||
<i class="bwi bwi-plus" aria-hidden="true"></i>
|
<i class="bwi bwi-plus tw-me-2" aria-hidden="true"></i>
|
||||||
{{ "new" | i18n }}
|
{{ "new" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<bit-menu #itemOptions>
|
<bit-menu #itemOptions>
|
||||||
|
|||||||
4
apps/desktop/desktop_native/Cargo.lock
generated
4
apps/desktop/desktop_native/Cargo.lock
generated
@@ -3189,9 +3189,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.35.0"
|
version = "0.37.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422"
|
checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ serde_json = "=1.0.127"
|
|||||||
sha2 = "=0.10.8"
|
sha2 = "=0.10.8"
|
||||||
ssh-encoding = "=0.2.0"
|
ssh-encoding = "=0.2.0"
|
||||||
ssh-key = { version = "=0.6.7", default-features = false }
|
ssh-key = { version = "=0.6.7", default-features = false }
|
||||||
sysinfo = "=0.35.0"
|
sysinfo = "=0.37.2"
|
||||||
thiserror = "=2.0.12"
|
thiserror = "=2.0.12"
|
||||||
tokio = "=1.45.0"
|
tokio = "=1.45.0"
|
||||||
tokio-util = "=0.7.13"
|
tokio-util = "=0.7.13"
|
||||||
|
|||||||
@@ -285,8 +285,8 @@ async fn windows_hello_authenticate_with_crypto(
|
|||||||
return Err(anyhow!("Failed to sign data"));
|
return Err(anyhow!("Failed to sign data"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let signature_buffer = signature.Result()?;
|
let mut signature_buffer = signature.Result()?;
|
||||||
let signature_value = unsafe { as_mut_bytes(&signature_buffer)? };
|
let signature_value = unsafe { as_mut_bytes(&mut signature_buffer)? };
|
||||||
|
|
||||||
// The signature is deterministic based on the challenge and keychain key. Thus, it can be
|
// The signature is deterministic based on the challenge and keychain key. Thus, it can be
|
||||||
// hashed to a key. It is unclear what entropy this key provides.
|
// hashed to a key. It is unclear what entropy this key provides.
|
||||||
@@ -368,7 +368,7 @@ fn decrypt_data(
|
|||||||
Ok(plaintext)
|
Ok(plaintext)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn as_mut_bytes(buffer: &IBuffer) -> Result<&mut [u8]> {
|
unsafe fn as_mut_bytes(buffer: &mut IBuffer) -> Result<&mut [u8]> {
|
||||||
let interop = buffer.cast::<IBufferByteAccess>()?;
|
let interop = buffer.cast::<IBufferByteAccess>()?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ serde_json = { workspace = true }
|
|||||||
tokio = { workspace = true, features = ["sync"] }
|
tokio = { workspace = true, features = ["sync"] }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true }
|
||||||
tracing-oslog = "0.3.0"
|
tracing-oslog = "=0.3.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
uniffi = { workspace = true, features = ["build"] }
|
uniffi = { workspace = true, features = ["build"] }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.87.0"
|
channel = "1.91.1"
|
||||||
components = [ "rustfmt", "clippy" ]
|
components = [ "rustfmt", "clippy" ]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ fn add_authenticator() -> std::result::Result<(), String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type EXPERIMENTAL_WebAuthNPluginAddAuthenticatorFnDeclaration = unsafe extern "cdecl" fn(
|
type EXPERIMENTAL_WebAuthNPluginAddAuthenticatorFnDeclaration = unsafe extern "C" fn(
|
||||||
pPluginAddAuthenticatorOptions: *const webauthn::ExperimentalWebAuthnPluginAddAuthenticatorOptions,
|
pPluginAddAuthenticatorOptions: *const webauthn::ExperimentalWebAuthnPluginAddAuthenticatorOptions,
|
||||||
ppPluginAddAuthenticatorResponse: *mut *mut webauthn::ExperimentalWebAuthnPluginAddAuthenticatorResponse,
|
ppPluginAddAuthenticatorResponse: *mut *mut webauthn::ExperimentalWebAuthnPluginAddAuthenticatorResponse,
|
||||||
) -> HRESULT;
|
) -> HRESULT;
|
||||||
|
|||||||
@@ -4392,5 +4392,8 @@
|
|||||||
"example": "Chrome"
|
"example": "Chrome"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"upgrade": {
|
||||||
|
"message": "Upgrade"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ import { BadgeModule } from "@bitwarden/components";
|
|||||||
type="button"
|
type="button"
|
||||||
*appNotPremium
|
*appNotPremium
|
||||||
bitBadge
|
bitBadge
|
||||||
variant="success"
|
[variant]="'primary'"
|
||||||
|
class="!tw-text-primary-600 !tw-border-primary-600"
|
||||||
(click)="promptForPremium($event)"
|
(click)="promptForPremium($event)"
|
||||||
>
|
>
|
||||||
{{ "premium" | i18n }}
|
<i class="bwi bwi-premium tw-pe-1"></i>{{ "upgrade" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
`,
|
`,
|
||||||
imports: [BadgeModule, JslibModule],
|
imports: [BadgeModule, JslibModule],
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default {
|
|||||||
provide: I18nService,
|
provide: I18nService,
|
||||||
useFactory: () => {
|
useFactory: () => {
|
||||||
return new I18nMockService({
|
return new I18nMockService({
|
||||||
premium: "Premium",
|
upgrade: "Upgrade",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -451,6 +451,24 @@ describe("ChipSelectComponent", () => {
|
|||||||
|
|
||||||
expect(disabledMenuItem?.disabled).toBe(true);
|
expect(disabledMenuItem?.disabled).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should handle writeValue called before options are initialized", async () => {
|
||||||
|
const testApp = fixture.componentInstance;
|
||||||
|
|
||||||
|
component["rootTree"] = null;
|
||||||
|
|
||||||
|
component.writeValue("opt1");
|
||||||
|
|
||||||
|
expect(component["pendingValue"]).toBe("opt1");
|
||||||
|
expect(component["selectedOption"]).toBeUndefined();
|
||||||
|
|
||||||
|
testApp.options.set(testOptions);
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
expect(component["selectedOption"]?.value).toBe("opt1");
|
||||||
|
expect(component["pendingValue"]).toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -100,10 +100,21 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor {
|
|||||||
/** Tree constructed from `this.options` */
|
/** Tree constructed from `this.options` */
|
||||||
private rootTree?: ChipSelectOption<T> | null;
|
private rootTree?: ChipSelectOption<T> | null;
|
||||||
|
|
||||||
|
/** Store the pending value when writeValue is called before options are initialized */
|
||||||
|
private pendingValue?: T;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Initialize the root tree whenever options change
|
// Initialize the root tree whenever options change
|
||||||
effect(() => {
|
effect(() => {
|
||||||
this.initializeRootTree(this.options());
|
this.initializeRootTree(this.options());
|
||||||
|
|
||||||
|
// If there's a pending value, apply it now that options are available
|
||||||
|
if (this.pendingValue !== undefined) {
|
||||||
|
this.selectedOption = this.findOption(this.rootTree, this.pendingValue);
|
||||||
|
this.setOrResetRenderedOptions();
|
||||||
|
this.pendingValue = undefined;
|
||||||
|
this.cdr.markForCheck();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Focus the first menu item when menuItems change (e.g., navigating submenus)
|
// Focus the first menu item when menuItems change (e.g., navigating submenus)
|
||||||
@@ -255,6 +266,12 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor {
|
|||||||
|
|
||||||
/** Implemented as part of NG_VALUE_ACCESSOR */
|
/** Implemented as part of NG_VALUE_ACCESSOR */
|
||||||
writeValue(obj: T): void {
|
writeValue(obj: T): void {
|
||||||
|
// If rootTree is not yet initialized, store the value to apply it later
|
||||||
|
if (!this.rootTree) {
|
||||||
|
this.pendingValue = obj;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.selectedOption = this.findOption(this.rootTree, obj);
|
this.selectedOption = this.findOption(this.rootTree, obj);
|
||||||
this.setOrResetRenderedOptions();
|
this.setOrResetRenderedOptions();
|
||||||
// OnPush components require manual change detection when writeValue() is called
|
// OnPush components require manual change detection when writeValue() is called
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<button bitButton [bitMenuTriggerFor]="itemOptions" [buttonType]="buttonType" type="button">
|
<button bitButton [bitMenuTriggerFor]="itemOptions" [buttonType]="buttonType" type="button">
|
||||||
<i *ngIf="!hideIcon" class="bwi bwi-plus" aria-hidden="true"></i>
|
<i *ngIf="!hideIcon" class="bwi bwi-plus tw-me-2" aria-hidden="true"></i>
|
||||||
{{ (hideIcon ? "createSend" : "new") | i18n }}
|
{{ (hideIcon ? "createSend" : "new") | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<bit-menu #itemOptions>
|
<bit-menu #itemOptions>
|
||||||
|
|||||||
@@ -122,7 +122,7 @@
|
|||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
<bit-form-field *ngIf="cipher.login.totp">
|
<bit-form-field *ngIf="cipher.login.totp">
|
||||||
<bit-label [appTextDrag]="totpCodeCopyObj?.totpCode">
|
<bit-label [appTextDrag]="totpCodeCopyObj?.totpCode">
|
||||||
<div class="tw-flex tw-items-center tw-gap-3">
|
<div class="tw-flex tw-items-center tw-gap-2">
|
||||||
{{ "verificationCodeTotp" | i18n }}
|
{{ "verificationCodeTotp" | i18n }}
|
||||||
<app-premium-badge [organizationId]="cipher.organizationId"></app-premium-badge>
|
<app-premium-badge [organizationId]="cipher.organizationId"></app-premium-badge>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user