Skip to content

Commit b940232

Browse files
author
MargeBot
committed
Merge branch 'IDTEAM-ipc-error-messages' into 'main'
Bubble IPC error messages up to renderer See merge request web/clients!16686
2 parents 013ef42 + 9ba9a90 commit b940232

File tree

21 files changed

+155
-125
lines changed

21 files changed

+155
-125
lines changed

applications/pass-desktop/native/src/biometrics/linux.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ impl super::BiometricsTrait for Biometrics {
77
bail!("Not implemented")
88
}
99

10-
fn get_decryption_key(_challenge_b64: Option<&str>) -> Result<[String; 2]> {
11-
bail!("Not implemented")
12-
}
13-
14-
fn check_presence(_handle: Vec<u8>, _reason: String) -> Result<bool> {
10+
fn check_presence(_handle: Vec<u8>, _reason: String) -> Result<()> {
1511
bail!("Not implemented")
1612
}
1713

applications/pass-desktop/native/src/biometrics/macos.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ impl super::BiometricsTrait for Biometrics {
1010
bail!("Not implemented")
1111
}
1212

13-
fn get_decryption_key(_challenge_b64: Option<&str>) -> Result<[String; 2]> {
14-
bail!("Not implemented")
15-
}
16-
17-
fn check_presence(_handle: Vec<u8>, _reason: String) -> Result<bool> {
13+
fn check_presence(_handle: Vec<u8>, _reason: String) -> Result<()> {
1814
bail!("Not implemented")
1915
}
2016

applications/pass-desktop/native/src/biometrics/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ mod biometrics_platform;
77

88
pub trait BiometricsTrait {
99
fn can_check_presence() -> Result<bool>;
10-
fn check_presence(handle: Vec<u8>, reason: String) -> Result<bool>;
11-
fn get_decryption_key(challenge: Option<&str>) -> Result<[String; 2]>;
10+
fn check_presence(handle: Vec<u8>, reason: String) -> Result<()>;
1211
fn get_secret(key: String) -> Result<Vec<u8>>;
1312
fn set_secret(key: String, data: Vec<u8>) -> Result<()>;
1413
fn delete_secret(key: String) -> Result<()>;

applications/pass-desktop/native/src/biometrics/windows.rs

Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -40,45 +40,7 @@ impl super::BiometricsTrait for Biometrics {
4040
}
4141
}
4242

43-
fn get_decryption_key(challenge_b64: Option<&str>) -> Result<[String; 2]> {
44-
static KEY_NAME: &HSTRING = h!("ProtonPass");
45-
46-
let challenge: [u8; 16] = match challenge_b64 {
47-
Some(str) => base64_engine
48-
.decode(str)?
49-
.try_into()
50-
.map_err(|_e| anyhow!("Invalid challenge"))?,
51-
None => random_challenge(),
52-
};
53-
54-
let open_result =
55-
KeyCredentialManager::RequestCreateAsync(KEY_NAME, KeyCredentialCreationOption::FailIfExists)?.get()?;
56-
57-
let retreive_result = match open_result.Status()? {
58-
KeyCredentialStatus::CredentialAlreadyExists => KeyCredentialManager::OpenAsync(KEY_NAME)?.get()?,
59-
KeyCredentialStatus::Success => open_result,
60-
_ => return Err(anyhow!("Failed to create key credential")),
61-
};
62-
63-
let credential = retreive_result.Credential()?;
64-
let challenge_buffer = CryptographicBuffer::CreateFromByteArray(&challenge)?;
65-
let signature_result = credential.RequestSignAsync(&challenge_buffer)?.get()?;
66-
ensure!(
67-
signature_result.Status()? == KeyCredentialStatus::Success,
68-
"Failed to sign data"
69-
);
70-
71-
let signature_buffer = signature_result.Result()?;
72-
let mut signature_value = Array::<u8>::with_len(signature_buffer.Length()? as usize);
73-
CryptographicBuffer::CopyToByteArray(&signature_buffer, &mut signature_value)?;
74-
75-
let key = Sha256::digest(&*signature_value);
76-
let key_b64 = base64_engine.encode(key);
77-
let iv_b64 = base64_engine.encode(challenge);
78-
Ok([key_b64, iv_b64])
79-
}
80-
81-
fn check_presence(handle: Vec<u8>, reason: String) -> Result<bool> {
43+
fn check_presence(handle: Vec<u8>, reason: String) -> Result<()> {
8244
let h = isize::from_le_bytes(handle.clone().try_into().unwrap());
8345
let window = HWND(h);
8446

@@ -88,8 +50,14 @@ impl super::BiometricsTrait for Biometrics {
8850
let result = operation.get()?;
8951

9052
match result {
91-
UserConsentVerificationResult::Verified => Ok(true),
92-
_ => Ok(false),
53+
UserConsentVerificationResult::Verified => Ok(),
54+
UserConsentVerificationResult::DeviceBusy => Err("Authentication device is busy."),
55+
UserConsentVerificationResult::DeviceNotPresent => Err("No authentication device found."),
56+
UserConsentVerificationResult::DisabledByPolicy => Err("Authentication device is disabled by policy."),
57+
UserConsentVerificationResult::NotConfiguredForUser => Err("No authentication device configured."),
58+
UserConsentVerificationResult::Canceled => Err("Authentication cancelled."),
59+
UserConsentVerificationResult::RetriesExhausted => Err("There have been too many failed attempts."),
60+
_ => Err("Biometric authentication failed."),
9361
}
9462
}
9563

applications/pass-desktop/native/src/lib.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,10 @@ pub mod biometric {
1616
}
1717

1818
#[napi]
19-
pub async fn check_presence(handle: Buffer, reason: String) -> napi::Result<bool> {
19+
pub async fn check_presence(handle: Buffer, reason: String) -> napi::Result<()> {
2020
Biometrics::check_presence(handle.into(), reason).map_err(|e| napi::Error::from_reason(e.to_string()))
2121
}
2222

23-
#[napi]
24-
pub async fn get_decryption_key(challenge: Option<&str>) -> napi::Result<Vec<String>> {
25-
Biometrics::get_decryption_key(challenge)
26-
.map(|v| v.into())
27-
.map_err(|e| napi::Error::from_reason(e.to_string()))
28-
}
29-
3023
#[napi]
3124
pub async fn get_secret(key: String) -> napi::Result<Uint8Array> {
3225
let vec = Biometrics::get_secret(key).map_err(|e| napi::Error::from_reason(e.to_string()))?;

applications/pass-desktop/src/app/App.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,8 @@ export const getPassCoreProps = (): PassCoreProviderProps => ({
8686
},
8787

8888
getBiometricsKey: async (store: AuthStore) => {
89-
try {
90-
const { storageKey, version } = inferBiometricsStorageKey(store);
91-
return (await window.ctxBridge?.getSecret(storageKey, version)) ?? null;
92-
} catch {
93-
return null;
94-
}
89+
const { storageKey, version } = inferBiometricsStorageKey(store);
90+
return (await window.ctxBridge?.getSecret(storageKey, version)) ?? null;
9591
},
9692

9793
generateBiometricsKey: async () => {

applications/pass-desktop/src/app/reportClientLaunch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default async () => {
1212
*/
1313
setMetricsEnabled(true);
1414

15-
const { installSource = null } = (await window.ctxBridge?.getInstallInfo()) ?? {};
15+
const installSource = (await window.ctxBridge?.getInstallInfo()) ?? null;
1616
if (installSource !== null) await reportClientLaunch(installSource, 'pass', api);
1717
void window.ctxBridge?.setInstallSourceReported();
1818
} catch (err) {

applications/pass-desktop/src/lib/biometrics/biometrics.macos.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,16 @@ import type { BiometricsFactory, BiometricsPlatformHandler } from './types';
88

99
const factory: BiometricsFactory = () => {
1010
/** reason is prefixed by 'Proton Pass wants to' */
11-
const checkPresence = async (reason = 'unlock') => {
12-
try {
13-
await systemPreferences.promptTouchID(reason);
14-
return true;
15-
} catch (_) {
16-
return false;
17-
}
18-
};
11+
const checkPresence = async (reason = 'unlock') => systemPreferences.promptTouchID(reason);
1912

2013
const biometrics: BiometricsPlatformHandler = {
2114
canCheckPresence: () => Promise.resolve(true),
2215
checkPresence: (_, reason) => checkPresence(reason),
2316
getDecryptionKey: () => Promise.resolve(null),
2417
getSecret: async (_, key, version) => {
25-
if (!(await checkPresence())) throw new Error('Biometric authentication failed');
18+
await checkPresence();
2619

27-
const secretBytes = await macBiometrics.getSecret(key).catch(() => null);
20+
const secretBytes = await macBiometrics.getSecret(key);
2821
if (!secretBytes) return null;
2922

3023
/** Version 1 (Legacy): Secrets were stored as UTF-8 encoded strings.

applications/pass-desktop/src/lib/biometrics/biometrics.windows.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ import type { BiometricsFactory, BiometricsPlatformHandler } from './types';
77
const factory: BiometricsFactory = (getWindow) => {
88
const checkPresence = async (reason = 'Proton Pass wants to unlock') => {
99
const handle = getWindow()?.getNativeWindowHandle();
10-
if (!handle) return false;
11-
return winBiometrics.checkPresence(handle, reason).catch(() => false);
10+
if (!handle) throw new Error('Failed to acquire window handle');
11+
await winBiometrics.checkPresence(handle, reason);
1212
};
1313

1414
const biometrics: BiometricsPlatformHandler = {
1515
canCheckPresence: () => winBiometrics.canCheckPresence().catch(() => false),
1616
checkPresence: (_, reason) => checkPresence(reason),
17-
getDecryptionKey: (_, challenge) => winBiometrics.getDecryptionKey(challenge).catch(() => null),
17+
getDecryptionKey: (_, challenge) => winBiometrics.getDecryptionKey(challenge),
1818
getSecret: async (_, key, version) => {
19-
if (!(await checkPresence())) throw new Error('Biometric authentication failed');
19+
await checkPresence();
2020

21-
const secretBytes = await winBiometrics.getSecret(key).catch(() => null);
21+
const secretBytes = await winBiometrics.getSecret(key);
2222
if (!secretBytes) return null;
2323

2424
/** Version 1 (Legacy): Secrets were stored as UTF-16 encoded strings in a Vec<u8>,

applications/pass-desktop/src/lib/biometrics/index.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1-
import { ipcMain } from 'electron';
21
import { platform } from 'os';
32

3+
import type { MaybeNull } from '@proton/pass/types';
4+
5+
import { setupIpcHandler } from '../ipc';
46
import type { BiometricsFactory, BiometricsPlatformHandler } from './types';
57

8+
declare module 'proton-pass-desktop/lib/ipc' {
9+
interface IPCChannels {
10+
'biometrics:canCheckPresence': IPCChannel<[], boolean>;
11+
'biometrics:checkPresence': IPCChannel<[reason?: string], void>;
12+
'biometrics:getDecryptionKey': IPCChannel<[challenge: string], MaybeNull<string[]>>;
13+
'biometrics:getSecret': IPCChannel<[key: string, version: number], MaybeNull<string>>;
14+
'biometrics:setSecret': IPCChannel<[key: string, secret: Uint8Array], void>;
15+
'biometrics:deleteSecret': IPCChannel<[key: string], void>;
16+
}
17+
}
18+
619
const factory: BiometricsFactory = (getWindow) => {
720
const platformImplementation: BiometricsPlatformHandler = (() => {
821
switch (platform()) {
@@ -22,12 +35,12 @@ const factory: BiometricsFactory = (getWindow) => {
2235
}
2336
})();
2437

25-
ipcMain.handle('biometrics:canCheckPresence', platformImplementation.canCheckPresence);
26-
ipcMain.handle('biometrics:checkPresence', platformImplementation.checkPresence);
27-
ipcMain.handle('biometrics:getDecryptionKey', platformImplementation.getDecryptionKey);
28-
ipcMain.handle('biometrics:getSecret', platformImplementation.getSecret);
29-
ipcMain.handle('biometrics:setSecret', platformImplementation.setSecret);
30-
ipcMain.handle('biometrics:deleteSecret', platformImplementation.deleteSecret);
38+
setupIpcHandler('biometrics:canCheckPresence', platformImplementation.canCheckPresence);
39+
setupIpcHandler('biometrics:checkPresence', platformImplementation.checkPresence);
40+
setupIpcHandler('biometrics:getDecryptionKey', platformImplementation.getDecryptionKey);
41+
setupIpcHandler('biometrics:getSecret', platformImplementation.getSecret);
42+
setupIpcHandler('biometrics:setSecret', platformImplementation.setSecret);
43+
setupIpcHandler('biometrics:deleteSecret', platformImplementation.deleteSecret);
3144

3245
return platformImplementation;
3346
};

0 commit comments

Comments
 (0)