1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-14 14:21:23 +00:00

Added remote wipe option when unlinking a device.

This commit is contained in:
Shuai Lin
2016-05-07 11:45:47 +08:00
committed by lian
parent 7514c587d5
commit 7dc7034de4
10 changed files with 93 additions and 13 deletions

View File

@@ -7,7 +7,7 @@ from rest_framework.exceptions import APIException
import seaserv
from seahub.base.accounts import User
from seahub.constants import GUEST_USER
from seahub.api2.models import Token, TokenV2
from seahub.api2.models import Token, TokenV2, WipedDevice
from seahub.api2.utils import get_client_ip
from seahub.utils import within_time_range
try:
@@ -28,6 +28,8 @@ class AuthenticationFailed(APIException):
def __init__(self, detail=None):
self.detail = detail or self.default_detail
class DeviceRemoteWipedException(AuthenticationFailed):
pass
class TokenAuthentication(BaseAuthentication):
"""
@@ -98,7 +100,15 @@ class TokenAuthentication(BaseAuthentication):
try:
token = TokenV2.objects.get(key=key)
except TokenV2.DoesNotExist:
return None # Continue authentication in token v1
try:
token = WipedDevice.objects.get(key=key)
except WipedDevice.DoesNotExist:
pass
else:
raise DeviceRemoteWipedException('Device set to be remote wiped')
# Continue authentication in token v1
return None
try:
user = User.objects.get(email=token.user)

25
seahub/api2/base.py Normal file
View File

@@ -0,0 +1,25 @@
#coding: UTF-8
from rest_framework.views import APIView as RestFrameworkAPIView
from seahub.api2.authentication import DeviceRemoteWipedException
class APIView(RestFrameworkAPIView):
"""
Subclass restframework's APIView to implement some custom feature like
adding a `X-Seafile-Wiped` header if the current client device has been
marked to be remote wiped by the user.
"""
def __init__(self, *a, **kw):
super(APIView, self).__init__(*a, **kw)
self._seafile_exc = None
def handle_exception(self, exc):
self._seafile_exc = exc
return super(APIView, self).handle_exception(exc)
def dispatch(self, *a, **kw):
response = super(APIView, self).dispatch(*a, **kw)
if self._seafile_exc and isinstance(self._seafile_exc, DeviceRemoteWipedException):
response['X-Seafile-Wiped'] = 'true'
return response

View File

@@ -1,7 +1,8 @@
import uuid
import hmac
import datetime
from hashlib import sha1
from django.db import models
from django.db import models, transaction
from seahub.base.fields import LowerCaseCharField
@@ -101,6 +102,14 @@ class TokenV2Manager(models.Manager):
def delete_device_token(self, username, platform, device_id):
super(TokenV2Manager, self).filter(user=username, platform=platform, device_id=device_id).delete()
def mark_device_to_be_remote_wiped(self, username, platform, device_id):
token = self._get_token_by_user_device(username, platform, device_id)
if not token:
return
with transaction.atomic():
wiped_device = WipedDevice(key=token.key)
wiped_device.save()
token.delete()
class TokenV2(models.Model):
"""
@@ -162,3 +171,8 @@ class TokenV2(models.Model):
platform_version=self.platform_version,
last_accessed=self.last_accessed,
last_login_ip=self.last_login_ip)
class WipedDevice(models.Model):
key = models.CharField(max_length=40, primary_key=True)
wiped_at = models.DateTimeField(auto_now=True)

View File

@@ -23,6 +23,7 @@ urlpatterns = patterns('',
url(r'^server-info/$', ServerInfoView.as_view()),
url(r'^logout-device/$', LogoutDeviceView.as_view()),
url(r'^client-login/$', ClientLoginTokenView.as_view()),
url(r'^device-wiped/$', RemoteWipeReportView.as_view()),
# RESTful API
url(r'^accounts/$', Accounts.as_view(), name="accounts"),

View File

@@ -16,7 +16,6 @@ from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.reverse import reverse
from rest_framework.response import Response
from rest_framework.views import APIView
from django.contrib.auth.hashers import check_password
from django.contrib.sites.models import RequestSite
@@ -40,6 +39,7 @@ from .utils import get_diff_details, \
api_repo_user_folder_perm_check, api_repo_setting_permission_check, \
api_repo_group_folder_perm_check
from seahub.api2.base import APIView
from seahub.avatar.templatetags.avatar_tags import api_avatar_url, avatar
from seahub.avatar.templatetags.group_avatar_tags import api_grp_avatar_url, \
grp_avatar
@@ -1914,6 +1914,7 @@ class DevicesView(APIView):
platform = request.data.get('platform', '')
device_id = request.data.get('device_id', '')
remote_wipe = request.data.get('wipe_device', '')
if not platform:
error_msg = 'platform invalid.'
@@ -1924,7 +1925,10 @@ class DevicesView(APIView):
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
do_unlink_device(request.user.username, platform, device_id)
do_unlink_device(request.user.username,
platform,
device_id,
remote_wipe=remote_wipe)
except SearpcError as e:
logger.error(e)
error_msg = 'Internal Server Error'
@@ -4534,3 +4538,20 @@ class RepoGroupFolderPerm(APIView):
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
class RemoteWipeReportView(APIView):
throttle_classes = (UserRateThrottle,)
@json_response
def post(self, request):
from seahub.api2.models import WipedDevice
token = request.POST.get('token', '')
if not token or len(token) != 40:
return api_error(status.HTTP_400_BAD_REQUEST, "device token is missing")
try:
entry = WipedDevice.objects.get(key=token)
entry.delete()
except WipedDevice.DoesNotExist:
return api_error(status.HTTP_400_BAD_REQUEST, "invalid device token")
return {}

View File

@@ -1,9 +1,9 @@
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from seaserv import seafile_api
from seahub import settings
from seahub.api2.base import APIView
from seahub.api2.throttling import AnonRateThrottle, UserRateThrottle
from seahub.api2.utils import json_response, api_error
from seahub.api2.authentication import TokenAuthentication

View File

@@ -1,5 +1,4 @@
from rest_framework.views import APIView
from seahub.api2.base import APIView
from seahub.api2.utils import json_response, is_seafile_pro
from seahub import settings
from seahub.utils import HAS_OFFICE_CONVERTER, HAS_FILE_SEARCH

View File

@@ -68,7 +68,7 @@ def get_user_synced_repo_infos(username):
return ret
def do_unlink_device(username, platform, device_id):
def do_unlink_device(username, platform, device_id, remote_wipe=False):
if platform in DESKTOP_PLATFORMS:
# For desktop client, we also remove the sync tokens
msg = 'failed to delete_repo_tokens_by_peer_id'
@@ -80,4 +80,7 @@ def do_unlink_device(username, platform, device_id):
logger.exception(msg)
raise
if remote_wipe:
TokenV2.objects.mark_device_to_be_remote_wiped(username, platform, device_id)
else:
TokenV2.objects.delete_device_token(username, platform, device_id)

View File

@@ -11,6 +11,9 @@ define([
'platform': this.get('platform'),
'device_id': this.get('device_id')
};
if (options.wipe_device) {
data['wipe_device'] = 'true';
}
$.ajax({
url: Common.getUrl({name: 'devices'}),

View File

@@ -73,9 +73,13 @@ define([
device_name = this.model.get('device_name');
var title = gettext('Unlink device');
var content = gettext('Are you sure you want to unlink this device?');
var extraOption = gettext('Delete files from this device the next time it comes online.');
var yesCallback = function () {
var yesCallback = function (wipe_device) {
console.log('wipe_device = ' + wipe_device);
_this.model.unlink({
wipe_device: wipe_device,
success: function() {
_this.remove();
@@ -92,7 +96,7 @@ define([
});
return false;
};
Common.showConfirm(title, content, yesCallback);
Common.showConfirmWithExtraOption(title, content, extraOption, yesCallback);
}
});