diff --git a/src/core/wopi.py b/src/core/wopi.py index d01f5384..1ffb4320 100644 --- a/src/core/wopi.py +++ b/src/core/wopi.py @@ -273,19 +273,10 @@ def setLock(fileid, reqheaders, acctok): if not retrievedLock or not utils.compareWopiLocks(retrievedLock, (oldLock if oldLock else lock)): # lock mismatch, the WOPI client is supposed to acknowledge the existing lock to start a collab session, # or deny access to the file in edit mode otherwise - evicted = False - if 'forcelock' in acctok and retrievedLock != 'External': - # here we try to evict the existing lock, and if possible we let the user go: - # this is to work around an issue with the Microsoft cloud! - evicted = utils.checkAndEvictLock(acctok['userid'], acctok['appname'], retrievedLock, oldLock, lock, - acctok['endpoint'], fn, int(statInfo['mtime'])) - if evicted: - return utils.makeLockSuccessResponse(op, acctok, lock, oldLock, f"v{statInfo['etag']}") - else: - return utils.makeConflictResponse(op, acctok['userid'], retrievedLock, lock, oldLock, fn, - 'The file is locked by %s' % - (lockHolder if lockHolder else 'another editor'), - savetime=savetime) + return utils.makeConflictResponse(op, acctok['userid'], retrievedLock, lock, oldLock, fn, + 'The file is locked by %s' % + (lockHolder if lockHolder else 'another editor'), + savetime=savetime) # else it's our own lock, refresh it (rechecking the oldLock if necessary, for atomicity) and return try: diff --git a/src/core/wopiutils.py b/src/core/wopiutils.py index 1a75fb24..65c6a16a 100644 --- a/src/core/wopiutils.py +++ b/src/core/wopiutils.py @@ -207,7 +207,7 @@ def randomString(size): return ''.join([choice(ascii_lowercase) for _ in range(size)]) -def generateAccessToken(userid, fileid, viewmode, user, folderurl, endpoint, app, forcelock=False): +def generateAccessToken(userid, fileid, viewmode, user, folderurl, endpoint, app): '''Generates an access token for a given file and a given user, and returns a tuple with the file's inode and the URL-encoded access token.''' appname, appediturl, appviewurl = app @@ -250,15 +250,13 @@ def generateAccessToken(userid, fileid, viewmode, user, folderurl, endpoint, app if statinfo['size'] == 0: # override preview mode when a new file is being created viewmode = ViewMode.READ_WRITE - if forcelock: - tokmd['forcelock'] = '1' acctok = jwt.encode(tokmd, srv.wopisecret, algorithm='HS256') if 'MS 365' in appname: srv.allusers.add(userid) log.info('msg="Access token generated" userid="%s" wopiuser="%s" friendlyname="%s" usertype="%s" mode="%s" ' - 'endpoint="%s" filename="%s" inode="%s" mtime="%s" folderurl="%s" appname="%s"%s expiration="%d" token="%s"' % + 'endpoint="%s" filename="%s" inode="%s" mtime="%s" folderurl="%s" appname="%s" expiration="%d" token="%s"' % (userid[-20:], wopiuser, friendlyname, usertype, viewmode, endpoint, statinfo['filepath'], statinfo['inode'], - statinfo['mtime'], folderurl, appname, ' forcelock="True"' if forcelock else '', exptime, acctok[-20:])) + statinfo['mtime'], folderurl, appname, exptime, acctok[-20:])) return statinfo['inode'], acctok, viewmode @@ -380,51 +378,6 @@ def compareWopiLocks(lock1, lock2): return False -def checkAndEvictLock(user, appname, retrievedlock, oldlock, lock, endpoint, filename, savetime): - '''Checks if the current lock can be evicted to overcome issue with Microsoft 365 cloud''' - evictlocktime = srv.config.get('general', 'evictlocktime', fallback='') - try: - evictlocktime = int(evictlocktime) - except ValueError: - return False - session = flask.request.headers.get('X-WOPI-SessionId') - if savetime > time.time() - evictlocktime: - # file is being edited, don't evict existing lock - log.warning('msg="File is actively edited, force-unlock prevented" lockop="%s" user="%s" ' - 'filename="%s" fileage="%1.1f" token="%s" sessionId="%s"' % - (('UnlockAndRelock' if oldlock else 'Lock'), user, filename, (time.time() - int(savetime)), - flask.request.args['access_token'][-20:], session)) - if session: - srv.conflictsessions['failedtotakeover'][session] = { - 'time': int(time.time()), - 'user': user - } - return False - # ok, remove current lock and set new one - try: - st.refreshlock(endpoint, filename, user, appname, encodeLock(lock), encodeLock(retrievedlock)) - except IOError as e: - log.error('msg="Failed to force a refreshlock" user="%s" filename="%s" error="%s" token="%s" sessionId="%s"' % - (user, filename, e, flask.request.args['access_token'][-20:], session)) - return False - # and note the stealer and the evicted sessions - if session not in srv.conflictsessions['tookover']: - try: - formersession = json.loads(retrievedlock)['S'] - except (TypeError, ValueError, KeyError): - formersession = retrievedlock - srv.conflictsessions['tookover'][session] = { - 'time': int(time.time()), - 'user': user, - 'former': formersession - } - log.warning('msg="Former session was evicted" lockop="%s" user="%s" filename="%s" fileage="%1.1f" ' - 'formerlock="%s" token="%s" newsession="%s"' % - (('UnlockAndRelock' if oldlock else 'Lock'), user, filename, (time.time() - int(savetime)), - retrievedlock, flask.request.args['access_token'][-20:], session)) - return True - - def makeConflictResponse(operation, user, retrievedlock, lock, oldlock, filename, reason, savetime=None): '''Generates and logs an HTTP 409 response in case of locks conflict''' resp = flask.Response(mimetype='application/json') diff --git a/src/wopiserver.py b/src/wopiserver.py index ce2e9f14..a39a7d79 100755 --- a/src/wopiserver.py +++ b/src/wopiserver.py @@ -283,7 +283,6 @@ def iopOpenInApp(): - string appurl: the URL of the end-user application - string appviewurl (optional): the URL of the end-user application in view mode when different (defaults to appurl) - string appinturl (optional): the internal URL of the end-user application (applicable with containerized deployments) - - string forcelock (optional): if present, will force the lock when possible to work around MS Office issues - string usertype (optional): one of "regular", "federated", "ocm", "anonymous". Defaults to "regular" Returns: a JSON response as follows: @@ -326,7 +325,6 @@ def iopOpenInApp(): appname = url_unquote_plus(req.args.get('appname', '')) appurl = url_unquote_plus(req.args.get('appurl', '')).strip('/') appviewurl = url_unquote_plus(req.args.get('appviewurl', appurl)).strip('/') - forcelock = req.args.get('forcelock', False) try: usertype = utils.UserType(req.args.get('usertype', utils.UserType.REGULAR)) except (KeyError, ValueError) as e: @@ -340,7 +338,7 @@ def iopOpenInApp(): try: userid, wopiuser = storage.getuseridfromcreds(usertoken, wopiuser) inode, acctok, vm = utils.generateAccessToken(userid, fileid, viewmode, (username, wopiuser, usertype), folderurl, - endpoint, (appname, appurl, appviewurl), forcelock=forcelock) + endpoint, (appname, appurl, appviewurl)) except IOError as e: Wopi.log.info('msg="iopOpenInApp: remote error on generating token" client="%s" user="%s" ' 'friendlyname="%s" mode="%s" endpoint="%s" reason="%s"' % diff --git a/wopiserver.conf b/wopiserver.conf index 4fbd0710..02e67762 100644 --- a/wopiserver.conf +++ b/wopiserver.conf @@ -93,13 +93,6 @@ wopilockexpiration = 1800 # on-premise setups. #wopilockstrictcheck = True -# Enable the ability to force-unlock sessions to overcome issues with Microsoft Office: -# if a session (access token) includes the option to override a previous lock, and the -# corresponding file was saved more than the given evictlocktime seconds before the request -# for lock, the previous lock is force-unlocked in order to grant a lock to the new -# session. By default this behavior is disabled. -#evictlocktime = - # Enable support of rename operations from WOPI apps. This is currently # disabled by default because the implementation is not complete, # and it is to be enabled for testing purposes only for the time being.