05/18 Enhanced codes and functionalities 2
This commit is contained in:
+1
-1
@@ -116,7 +116,7 @@ def login():
|
|||||||
# Columns do not exist yet — migration pending. Skip lockout check.
|
# Columns do not exist yet — migration pending. Skip lockout check.
|
||||||
db.session.rollback()
|
db.session.rollback()
|
||||||
|
|
||||||
if not user or not verify_auth_token(auth_hash, user.master_hash):
|
if not user or not verify_auth_token(auth_hash, user.master_hash, user=user):
|
||||||
if user:
|
if user:
|
||||||
try:
|
try:
|
||||||
user.failed_login_count = (user.failed_login_count or 0) + 1
|
user.failed_login_count = (user.failed_login_count or 0) + 1
|
||||||
|
|||||||
+6
-6
@@ -83,7 +83,7 @@ def create_item():
|
|||||||
action='vault_item.create',
|
action='vault_item.create',
|
||||||
resource_type='vault_item',
|
resource_type='vault_item',
|
||||||
resource_id=item.id,
|
resource_id=item.id,
|
||||||
detail=f'Created {item_type} item: "{name}"',
|
detail=f'Created {item_type} item (id={item.id})',
|
||||||
ip_address=client_ip(),
|
ip_address=client_ip(),
|
||||||
)
|
)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@@ -144,7 +144,7 @@ def update_item(item_id):
|
|||||||
action='vault_item.update',
|
action='vault_item.update',
|
||||||
resource_type='vault_item',
|
resource_type='vault_item',
|
||||||
resource_id=item.id,
|
resource_id=item.id,
|
||||||
detail=f'Updated item: "{item.name}"',
|
detail=f'Updated {item.item_type} item (id={item.id})',
|
||||||
ip_address=client_ip(),
|
ip_address=client_ip(),
|
||||||
)
|
)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@@ -162,16 +162,16 @@ def delete_item(item_id):
|
|||||||
item = VaultItem.query.filter_by(id=item_id, user_id=g.current_user_id).first()
|
item = VaultItem.query.filter_by(id=item_id, user_id=g.current_user_id).first()
|
||||||
if not item:
|
if not item:
|
||||||
return jsonify({'error': 'Item not found'}), 404
|
return jsonify({'error': 'Item not found'}), 404
|
||||||
item_name = item.name
|
item_id_saved = item.id
|
||||||
item_id = item.id
|
item_type_saved = item.item_type
|
||||||
db.session.delete(item)
|
db.session.delete(item)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
AuditLog.log(
|
AuditLog.log(
|
||||||
user_id=g.current_user_id,
|
user_id=g.current_user_id,
|
||||||
action='vault_item.delete',
|
action='vault_item.delete',
|
||||||
resource_type='vault_item',
|
resource_type='vault_item',
|
||||||
resource_id=item_id,
|
resource_id=item_id_saved,
|
||||||
detail=f'Deleted item: "{item_name}"',
|
detail=f'Deleted {item_type_saved} item (id={item_id_saved})',
|
||||||
ip_address=client_ip(),
|
ip_address=client_ip(),
|
||||||
)
|
)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|||||||
@@ -24,10 +24,24 @@ def hash_auth_token(auth_hash: str) -> str:
|
|||||||
return ph.hash(auth_hash)
|
return ph.hash(auth_hash)
|
||||||
|
|
||||||
|
|
||||||
def verify_auth_token(auth_hash: str, stored_hash: str) -> bool:
|
def verify_auth_token(auth_hash: str, stored_hash: str, user=None) -> bool:
|
||||||
|
"""
|
||||||
|
Verify auth_hash against stored Argon2id hash.
|
||||||
|
If user is provided and the stored hash uses outdated parameters,
|
||||||
|
the hash is transparently upgraded on successful verification.
|
||||||
|
Caller must commit the session after this returns True.
|
||||||
|
"""
|
||||||
ph = PasswordHasher()
|
ph = PasswordHasher()
|
||||||
try:
|
try:
|
||||||
return ph.verify(stored_hash, auth_hash)
|
result = ph.verify(stored_hash, auth_hash)
|
||||||
|
if result and user is not None and ph.check_needs_rehash(stored_hash):
|
||||||
|
ph_fresh = PasswordHasher(
|
||||||
|
time_cost=current_app.config['ARGON2_TIME_COST'],
|
||||||
|
memory_cost=current_app.config['ARGON2_MEMORY_COST'],
|
||||||
|
parallelism=current_app.config['ARGON2_PARALLELISM'],
|
||||||
|
)
|
||||||
|
user.master_hash = ph_fresh.hash(auth_hash)
|
||||||
|
return result
|
||||||
except (VerifyMismatchError, VerificationError, InvalidHashError):
|
except (VerifyMismatchError, VerificationError, InvalidHashError):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
+20
-5
@@ -931,13 +931,22 @@ const Vault = (() => {
|
|||||||
for (let i = 1; i < lines.length; i++) {
|
for (let i = 1; i < lines.length; i++) {
|
||||||
const line = lines[i].trim();
|
const line = lines[i].trim();
|
||||||
if (!line) continue;
|
if (!line) continue;
|
||||||
// Simple CSV split — handles quoted fields containing commas.
|
// RFC 4180-compliant CSV split — handles quoted fields containing commas
|
||||||
|
// and embedded double-quotes escaped as "".
|
||||||
const cells = [];
|
const cells = [];
|
||||||
let cur = "",
|
let cur = "",
|
||||||
inQuote = false;
|
inQuote = false;
|
||||||
for (const ch of line + ",") {
|
const src = line + ",";
|
||||||
|
for (let ci = 0; ci < src.length; ci++) {
|
||||||
|
const ch = src[ci];
|
||||||
if (ch === '"') {
|
if (ch === '"') {
|
||||||
|
if (inQuote && src[ci + 1] === '"') {
|
||||||
|
// Escaped quote inside a quoted field: "" → "
|
||||||
|
cur += '"';
|
||||||
|
ci++; // skip the second quote
|
||||||
|
} else {
|
||||||
inQuote = !inQuote;
|
inQuote = !inQuote;
|
||||||
|
}
|
||||||
} else if (ch === "," && !inQuote) {
|
} else if (ch === "," && !inQuote) {
|
||||||
cells.push(cur.trim());
|
cells.push(cur.trim());
|
||||||
cur = "";
|
cur = "";
|
||||||
@@ -2856,10 +2865,16 @@ const Vault = (() => {
|
|||||||
applyCurrentFilter();
|
applyCurrentFilter();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const pool = _activeFilter
|
const pool = !_activeFilter
|
||||||
? _activeFilter.type === "itemType"
|
? _items
|
||||||
|
: _activeFilter.type === "itemType"
|
||||||
? _items.filter((i) => i.item_type === _activeFilter.value)
|
? _items.filter((i) => i.item_type === _activeFilter.value)
|
||||||
: _items.filter((i) => i.folder_id === _activeFilter.value)
|
: _activeFilter.type === "folder"
|
||||||
|
? _items.filter((i) => i.folder_id === _activeFilter.value)
|
||||||
|
: _activeFilter.type === "tag"
|
||||||
|
? _items.filter((i) =>
|
||||||
|
(i.plain?.tags || []).includes(_activeFilter.value),
|
||||||
|
)
|
||||||
: _items;
|
: _items;
|
||||||
renderItemList(
|
renderItemList(
|
||||||
pool.filter(
|
pool.filter(
|
||||||
|
|||||||
Reference in New Issue
Block a user