1
0
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:
John Harrington
2025-12-09 09:10:08 -07:00
committed by GitHub
16 changed files with 61 additions and 19 deletions

View File

@@ -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

View File

@@ -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"
} }
} }

View File

@@ -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>

View File

@@ -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",

View File

@@ -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"

View File

@@ -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 {

View File

@@ -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"] }

View File

@@ -1,4 +1,4 @@
[toolchain] [toolchain]
channel = "1.87.0" channel = "1.91.1"
components = [ "rustfmt", "clippy" ] components = [ "rustfmt", "clippy" ]
profile = "minimal" profile = "minimal"

View File

@@ -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;

View File

@@ -4392,5 +4392,8 @@
"example": "Chrome" "example": "Chrome"
} }
} }
},
"upgrade": {
"message": "Upgrade"
} }
} }

View File

@@ -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],

View File

@@ -29,7 +29,7 @@ export default {
provide: I18nService, provide: I18nService,
useFactory: () => { useFactory: () => {
return new I18nMockService({ return new I18nMockService({
premium: "Premium", upgrade: "Upgrade",
}); });
}, },
}, },

View File

@@ -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();
});
}); });
}); });

View File

@@ -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

View File

@@ -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>

View File

@@ -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>