implement patches
This commit is contained in:
+56
-8
@@ -2,18 +2,23 @@ from flask import Blueprint, request, jsonify, g
|
||||
from app import db
|
||||
from app.models.user import User
|
||||
from app.models.shared_item import SharedItem
|
||||
from app.models.audit_log import AuditLog
|
||||
from app.services.auth_service import require_jwt
|
||||
|
||||
sharing_bp = Blueprint('sharing', __name__)
|
||||
|
||||
|
||||
def _client_ip():
|
||||
return request.headers.get('X-Forwarded-For', request.remote_addr or '').split(',')[0].strip()
|
||||
|
||||
|
||||
# ── Sharing keypair management ────────────────────────────────────────────────
|
||||
|
||||
@sharing_bp.route('/keys', methods=['GET'])
|
||||
@require_jwt
|
||||
def get_my_keys():
|
||||
"""Return current user's encrypted sharing private key (to decrypt client-side)."""
|
||||
user = User.query.get(g.current_user_id)
|
||||
user = db.session.get(User, g.current_user_id)
|
||||
if not user.sharing_public_key:
|
||||
return jsonify({'keys_setup': False}), 200
|
||||
return jsonify({
|
||||
@@ -36,10 +41,20 @@ def store_my_keys():
|
||||
if not public_key or not private_key_enc or not private_key_iv:
|
||||
return jsonify({'error': 'public_key, private_key_enc, and private_key_iv are required'}), 400
|
||||
|
||||
user = User.query.get(g.current_user_id)
|
||||
user = db.session.get(User, g.current_user_id)
|
||||
action = 'sharing_keys.update' if user.sharing_public_key else 'sharing_keys.create'
|
||||
user.sharing_public_key = public_key
|
||||
user.sharing_private_key_enc = private_key_enc
|
||||
user.sharing_private_key_iv = private_key_iv
|
||||
|
||||
AuditLog.log(
|
||||
user_id=g.current_user_id,
|
||||
action=action,
|
||||
resource_type='sharing_keys',
|
||||
resource_id=g.current_user_id,
|
||||
detail='ECDH sharing keypair stored/updated',
|
||||
ip_address=_client_ip(),
|
||||
)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({'message': 'Sharing keys stored'}), 200
|
||||
@@ -81,7 +96,7 @@ def list_outgoing():
|
||||
result = []
|
||||
for s in shares:
|
||||
d = s.to_dict()
|
||||
recipient = User.query.get(s.recipient_id) if s.recipient_id else None
|
||||
recipient = db.session.get(User, s.recipient_id) if s.recipient_id else None
|
||||
d['recipient_name'] = recipient.email if recipient else s.recipient_email
|
||||
result.append(d)
|
||||
return jsonify(result), 200
|
||||
@@ -110,7 +125,7 @@ def create_share():
|
||||
if not all([item_id, recipient_email, enc_data, iv, item_name]):
|
||||
return jsonify({'error': 'item_id, recipient_email, enc_data, iv, item_name are required'}), 400
|
||||
|
||||
owner = User.query.get(g.current_user_id)
|
||||
owner = db.session.get(User, g.current_user_id)
|
||||
if owner.email == recipient_email:
|
||||
return jsonify({'error': 'Cannot share an item with yourself'}), 400
|
||||
|
||||
@@ -133,6 +148,16 @@ def create_share():
|
||||
iv=iv,
|
||||
)
|
||||
db.session.add(share)
|
||||
db.session.flush() # populate share.id before logging
|
||||
|
||||
AuditLog.log(
|
||||
user_id=g.current_user_id,
|
||||
action='shared_item.create',
|
||||
resource_type='shared_item',
|
||||
resource_id=share.id,
|
||||
detail=f'Shared item "{item_name}" ({item_type}) with {recipient_email}',
|
||||
ip_address=_client_ip(),
|
||||
)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify(share.to_dict()), 201
|
||||
@@ -144,7 +169,20 @@ def delete_share(share_id):
|
||||
share = SharedItem.query.filter_by(id=share_id, owner_id=g.current_user_id).first()
|
||||
if not share:
|
||||
return jsonify({'error': 'Share not found'}), 404
|
||||
|
||||
item_name = share.item_name
|
||||
recipient_email = share.recipient_email
|
||||
db.session.delete(share)
|
||||
db.session.flush()
|
||||
|
||||
AuditLog.log(
|
||||
user_id=g.current_user_id,
|
||||
action='shared_item.delete',
|
||||
resource_type='shared_item',
|
||||
resource_id=share_id,
|
||||
detail=f'Revoked share of "{item_name}" with {recipient_email}',
|
||||
ip_address=_client_ip(),
|
||||
)
|
||||
db.session.commit()
|
||||
return jsonify({'message': 'Share removed'}), 200
|
||||
|
||||
@@ -155,7 +193,7 @@ def delete_share(share_id):
|
||||
@require_jwt
|
||||
def inbox():
|
||||
"""List all items shared with the current user."""
|
||||
user = User.query.get(g.current_user_id)
|
||||
user = db.session.get(User, g.current_user_id)
|
||||
shares = (
|
||||
SharedItem.query
|
||||
.filter(
|
||||
@@ -170,7 +208,7 @@ def inbox():
|
||||
result = []
|
||||
for s in shares:
|
||||
d = s.to_dict()
|
||||
owner = User.query.get(s.owner_id)
|
||||
owner = db.session.get(User, s.owner_id)
|
||||
d['owner_email'] = owner.email if owner else 'Unknown'
|
||||
d['owner_public_key'] = owner.sharing_public_key if owner else None
|
||||
result.append(d)
|
||||
@@ -181,7 +219,7 @@ def inbox():
|
||||
@require_jwt
|
||||
def accept_share(share_id):
|
||||
"""Mark a received share as accepted (links recipient_id if not already set)."""
|
||||
user = User.query.get(g.current_user_id)
|
||||
user = db.session.get(User, g.current_user_id)
|
||||
share = SharedItem.query.filter(
|
||||
SharedItem.id == share_id,
|
||||
db.or_(
|
||||
@@ -194,10 +232,20 @@ def accept_share(share_id):
|
||||
|
||||
share.accepted = True
|
||||
share.recipient_id = user.id
|
||||
|
||||
AuditLog.log(
|
||||
user_id=g.current_user_id,
|
||||
action='shared_item.accept',
|
||||
resource_type='shared_item',
|
||||
resource_id=share.id,
|
||||
detail=f'Accepted shared item "{share.item_name}" from {share.recipient_email}',
|
||||
ip_address=_client_ip(),
|
||||
)
|
||||
db.session.commit()
|
||||
|
||||
d = share.to_dict()
|
||||
owner = User.query.get(share.owner_id)
|
||||
owner = db.session.get(User, share.owner_id)
|
||||
d['owner_email'] = owner.email if owner else 'Unknown'
|
||||
d['owner_public_key'] = owner.sharing_public_key if owner else None
|
||||
return jsonify(d), 200
|
||||
|
||||
|
||||
Reference in New Issue
Block a user