Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e379ef5
feat(lock): implement application lock functionality with IPC integra…
CorneiZeR Oct 7, 2025
d2fd6eb
Harden lock BrowserView: disable Node, enable isolation; remove runti…
CorneiZeR Oct 7, 2025
6bd0862
Add simple throttling to deter brute‑force attempts via 'lock:verify'
CorneiZeR Oct 7, 2025
f84689a
Anyone can call 'lock:unlock' from any renderer; gate it to the lock …
CorneiZeR Oct 7, 2025
62b717a
Listeners may never attach if root window isn’t ready; retry until av…
CorneiZeR Oct 7, 2025
b11d220
Critical: Incorrect i18n structure for lockScreen.
CorneiZeR Oct 7, 2025
5eedd06
Critical: Incorrect i18n structure for lockScreen.
CorneiZeR Oct 7, 2025
86dfb24
Critical: Incorrect i18n structure for lockScreen.
CorneiZeR Oct 7, 2025
256421f
Refine Norwegian phrasing for the timeout description
CorneiZeR Oct 7, 2025
6d119c7
Align zh-TW wording with existing style.
CorneiZeR Oct 7, 2025
3aefe09
Keep terminology consistent with rest of locale.
CorneiZeR Oct 7, 2025
64285f1
Critical: Incorrect i18n structure for lockScreen.
CorneiZeR Oct 7, 2025
1f36836
Guard missing electron API to avoid false “incorrect” errors.
CorneiZeR Oct 7, 2025
3778dfb
Sync local input state with store updates
CorneiZeR Oct 7, 2025
62fef32
Strengthen password storage: use salted, slow hash (scrypt/pbkdf2), n…
CorneiZeR Oct 7, 2025
253afec
Replace plain SHA-256 hashing with a salted KDF for screenLockPasswor…
CorneiZeR Oct 7, 2025
612c301
Refactor screen lock password handling: use secure IPC for hashing an…
CorneiZeR Oct 8, 2025
9a2ffde
Implement screen lock state management: add actions, reducer, and IPC…
CorneiZeR Oct 8, 2025
173792f
Align wording with new hashing implementation.
CorneiZeR Oct 8, 2025
da6963c
Avoid starting the timer when root window isn’t ready; retry focus ch…
CorneiZeR Oct 8, 2025
db21c13
Restrict lock:set IPC handler to authorized renderers
CorneiZeR Oct 8, 2025
41b9efa
Enforce origin checks and rate-limit on lock IPC handlers
CorneiZeR Oct 8, 2025
74f4243
Race between GRACE_WINDOW_MS and MIN_CLEAR_IGNORE_MS can cause false …
CorneiZeR Oct 8, 2025
785a92d
Remove direct electron import from renderer code
CorneiZeR Oct 8, 2025
283980b
fix lock work
CorneiZeR Oct 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ insert_final_newline = true
indent_style = space
indent_size = 2

[*.json]
insert_final_newline = false

[*.md]
trim_trailing_whitespace = false
34 changes: 34 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,40 @@ export default [
},
],
},
{
// Lock screen renderer bundle
external: [
...builtinModules,
...Object.keys(appManifest.dependencies),
...Object.keys(appManifest.devDependencies),
].filter((moduleName) => moduleName !== '@bugsnag/js'),
input: 'src/lockScreen/lock-screen.tsx',
preserveEntrySignatures: 'strict',
plugins: [
json(),
replace({
'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
'preventAssignment': true,
}),
babel({
babelHelpers: 'bundled',
extensions,
}),
nodeResolve({
browser: true,
extensions,
}),
commonjs(),
],
output: [
{
dir: 'app',
format: 'cjs',
sourcemap: 'inline',
interop: 'auto',
},
],
},
{
external: [
...builtinModules,
Expand Down
93 changes: 91 additions & 2 deletions src/app/PersistableValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,22 @@ type PersistableValues_4_9_0 = PersistableValues_4_7_2 & {
isVideoCallScreenCaptureFallbackEnabled: boolean;
};

// Add screen lock persisted settings: timeout (seconds) and passwordHash (now an object with algorithm, hash, salt, params)
export type ScreenLockPasswordStored = {
algorithm: string; // e.g. 'scrypt', 'pbkdf2', 'legacy-sha256'
hash: string; // base64 encoded derived key or legacy hex encoded then base64
salt: string; // base64 encoded salt (or empty string for legacy where salt wasn't used)
params?: Record<string, any>; // algorithm-specific params (iterations, keylen, maxmem, digest, etc.)
};

type PersistableValues_5_0_0 = PersistableValues_4_9_0 & {
screenLockTimeoutSeconds: number; // 0 = disabled
screenLockPasswordHash: ScreenLockPasswordStored | null;
};

export type PersistableValues = Pick<
PersistableValues_4_9_0,
keyof PersistableValues_4_9_0
PersistableValues_5_0_0,
keyof PersistableValues_5_0_0
>;

export const migrations = {
Expand Down Expand Up @@ -171,4 +184,80 @@ export const migrations = {
...before,
isVideoCallScreenCaptureFallbackEnabled: false,
}),
// New migration for screen lock defaults (initial addition)
'>=5.0.0': (before: PersistableValues_4_9_0): PersistableValues_5_0_0 => ({
...before,
screenLockTimeoutSeconds: 0,
screenLockPasswordHash: null,
}),
// Convert older plain sha256 hex or legacy pbkdf2 string into structured object
'>=5.0.1': (before: any): PersistableValues_5_0_0 => {
// If there is no prior screen lock value, keep as null
const raw = (before && before.screenLockPasswordHash) || null;

if (!raw) {
return {
...before,
screenLockTimeoutSeconds: before.screenLockTimeoutSeconds ?? 0,
screenLockPasswordHash: null,
};
}

// If already an object with algorithm, assume it's in new format
if (typeof raw === 'object' && raw.algorithm) {
return {
...before,
screenLockTimeoutSeconds: before.screenLockTimeoutSeconds ?? 0,
screenLockPasswordHash: raw as ScreenLockPasswordStored,
};
}

// If string: could be legacy sha256 hex (64 hex chars) or our old pbkdf2$... encoded string
if (typeof raw === 'string') {
// pbkdf2 encoded string format: pbkdf2$<digest>$i=<iterations>$s=<saltHex>$d=<derivedHex>
const pbkdf2Match =
/^pbkdf2\$(\w+)\$i=(\d+)\$s=([0-9a-f]+)\$d=([0-9a-f]+)$/.exec(raw);
if (pbkdf2Match) {
const [, digest, itStr, saltHex, derivedHex] = pbkdf2Match;
const saltBuf = Buffer.from(saltHex, 'hex');
const derivedBuf = Buffer.from(derivedHex, 'hex');
return {
...before,
screenLockTimeoutSeconds: before.screenLockTimeoutSeconds ?? 0,
screenLockPasswordHash: {
algorithm: 'pbkdf2',
hash: derivedBuf.toString('base64'),
salt: saltBuf.toString('base64'),
params: {
iterations: Number(itStr),
digest,
keylen: derivedBuf.length,
},
},
};
}

// legacy unsalted sha256 hex
if (/^[0-9a-f]{64}$/.test(raw)) {
const buf = Buffer.from(raw, 'hex');
return {
...before,
screenLockTimeoutSeconds: before.screenLockTimeoutSeconds ?? 0,
screenLockPasswordHash: {
algorithm: 'legacy-sha256',
hash: buf.toString('base64'),
salt: '',
params: {},
},
};
}
}

// Unknown format — drop it and require user to reset password
return {
...before,
screenLockTimeoutSeconds: before.screenLockTimeoutSeconds ?? 0,
screenLockPasswordHash: null,
};
},
};
Loading