diff --git a/dist/index.html b/dist/index.html
index 4a8c710..76f7aff 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -2326,6 +2326,20 @@ function merge_text_nodes(text) {
//#endregion
//#region node_modules/svelte/src/internal/client/dom/elements/misc.js
/**
+* @param {HTMLElement} dom
+* @param {boolean} value
+* @returns {void}
+*/
+function autofocus(dom, value) {
+ if (value) {
+ const body = document.body;
+ dom.autofocus = true;
+ queue_micro_task(() => {
+ if (document.activeElement === body) dom.focus();
+ });
+ }
+}
+/**
* The child of a textarea actually corresponds to the defaultValue property, so we need
* to remove it upon hydration to avoid a bug when someone resets the form value.
* @param {HTMLTextAreaElement} dom
@@ -4817,7 +4831,10 @@ var app$1 = new AppStore();
* @returns {string}
*/
function generateId() {
- return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
+ const timestamp = Date.now().toString(36);
+ const randomBytes = new Uint8Array(4);
+ crypto.getRandomValues(randomBytes);
+ return `${timestamp}_${Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8)}`;
}
/**
* @typedef {Object} CredentialEntry
@@ -4955,7 +4972,7 @@ function validateGroup(name) {
*
* The derived encryption key is kept in memory only — never written to disk.
*/
-var PBKDF2_ITERATIONS = 1e5;
+var PBKDF2_ITERATIONS = 6e5;
var SALT_LENGTH = 16;
var IV_LENGTH = 12;
/**
@@ -5088,9 +5105,19 @@ function generatePassword({ length = 16, uppercase = true, lowercase = true, dig
charset = charset.split("").filter((c) => !excludeSet.has(c)).join("");
}
if (!charset) throw new Error("Password charset is empty — enable at least one character type");
- const randomValues = crypto.getRandomValues(new Uint8Array(length));
+ const charsetLength = charset.length;
+ const maxValid = 256 - 256 % charsetLength;
+ const randomBytes = new Uint8Array(length * 2);
let password = "";
- for (let i = 0; i < length; i++) password += charset[randomValues[i] % charset.length];
+ let byteIdx = 0;
+ while (password.length < length) {
+ if (byteIdx >= randomBytes.length) {
+ crypto.getRandomValues(randomBytes);
+ byteIdx = 0;
+ }
+ const byte = randomBytes[byteIdx++];
+ if (byte < maxValid) password += charset[byte % charsetLength];
+ }
return password;
}
//#endregion
@@ -5536,17 +5563,6 @@ async function exportAll() {
};
}
/**
-* Convert a base64 string back to Uint8Array.
-* @param {string} base64
-* @returns {Uint8Array}
-*/
-function base64ToUint8Array(base64) {
- const binary = atob(base64);
- const bytes = new Uint8Array(binary.length);
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
- return bytes;
-}
-/**
* Import data from a previously exported JSON object.
*
* Requires the source vault's master password to decrypt entries, then
@@ -5682,6 +5698,7 @@ function LockScreen($$anchor, $$props) {
var div_3 = child(form);
var input = sibling(child(div_3), 2);
remove_input_defaults(input);
+ autofocus(input, true);
reset(div_3);
var node_1 = sibling(div_3, 2);
var consequent_1 = ($$anchor) => {
diff --git a/src/components/LockScreen.svelte b/src/components/LockScreen.svelte
index 4630bfb..d453c94 100644
--- a/src/components/LockScreen.svelte
+++ b/src/components/LockScreen.svelte
@@ -95,6 +95,7 @@
bind:value={masterPassword}
placeholder="Enter master password"
autocomplete="current-password"
+ autofocus
disabled={loading}
/>