Add timestamp WOPI checking

Change status error code to 500.
This commit is contained in:
Jure Grabnar 2016-09-22 16:18:57 +02:00
parent b51f2a3027
commit 674326e761
3 changed files with 70 additions and 50 deletions

View file

@ -1,22 +1,24 @@
class WopiController < ActionController::Base
include WopiUtil
before_action :load_vars,:authenticate_user_from_token!
before_action :verify_proof!
def get_file_endpoint
Rails.logger.warn "get_file called"
logger.warn "get_file called"
#Only used for checkfileinfo
check_file_info
end
def get_file_contents_endpoint
Rails.logger.warn "get_file_contents called"
logger.warn "get_file_contents called"
#Only used for getfile
get_file
end
def post_file_endpoint
Rails.logger.warn "post_file called"
logger.warn "post_file called"
override = request.headers["X-WOPI-Override"]
case override
when "GET_LOCK"
@ -40,13 +42,13 @@ class WopiController < ActionController::Base
end
def post_file_contents_endpoint
Rails.logger.warn "post_file_contents called"
logger.warn "post_file_contents called"
#Only used for putfile
put_file
end
def check_file_info
Rails.logger.warn "Check file info started"
logger.warn "Check file info started"
msg = { :BaseFileName => @asset.file_file_name,
:OwnerId => @asset.created_by_id.to_s,
:Size => @asset.file_file_size,
@ -79,19 +81,19 @@ class WopiController < ActionController::Base
end
def get_file
Rails.logger.warn "getting file"
logger.warn "getting file"
response.headers["X-WOPI-ItemVersion"] = @asset.version
response.body = Paperclip.io_adapters.for(@asset.file).read
send_data response.body, disposition: "inline", :content_type => 'text/plain'
end
def put_relative
Rails.logger.warn "put relative"
logger.warn "put relative"
render :nothing => true, :status => 501 and return
end
def lock
Rails.logger.warn "lock"
logger.warn "lock"
lock = request.headers["X-WOPI-Lock"]
if lock.nil? || lock.blank?
render :nothing => true, :status => 400 and return
@ -115,7 +117,7 @@ class WopiController < ActionController::Base
end
def unlock_and_relock
Rails.logger.warn "lock and relock"
logger.warn "lock and relock"
lock = request.headers["X-WOPI-Lock"]
old_lock = request.headers["X-WOPI-OldLock"]
if lock.nil? || lock.blank? || old_lock.blank?
@ -140,14 +142,14 @@ class WopiController < ActionController::Base
end
def unlock
Rails.logger.warn "unlock"
logger.warn "unlock"
lock = request.headers["X-WOPI-Lock"]
if lock.nil? || lock.blank?
render :nothing => true, :status => 400 and return
end
@asset.with_lock do
if @asset.is_locked
Rails.logger.warn "Current asset lock: #{@asset.lock}, unlocking lock #{lock}"
logger.warn "Current asset lock: #{@asset.lock}, unlocking lock #{lock}"
if @asset.lock == lock
@asset.unlock
response.headers["X-WOPI-ItemVersion"] = @asset.version
@ -157,7 +159,7 @@ class WopiController < ActionController::Base
render :nothing => true, :status => 409 and return
end
else
Rails.logger.warn "Tried to unlock non-locked file"
logger.warn "Tried to unlock non-locked file"
response.headers["X-WOPI-Lock"] = ""
render :nothing => true, :status => 409 and return
end
@ -165,7 +167,7 @@ class WopiController < ActionController::Base
end
def refresh_lock
Rails.logger.warn "refresh lock"
logger.warn "refresh lock"
lock = request.headers["X-WOPI-Lock"]
if lock.nil? || lock.blank?
render :nothing => true, :status => 400 and return
@ -189,7 +191,7 @@ class WopiController < ActionController::Base
end
def get_lock
Rails.logger.warn "get lock"
logger.warn "get lock"
@asset.with_lock do
if @asset.is_locked
response.headers["X-WOPI-Lock"] = @asset.lock
@ -202,28 +204,28 @@ class WopiController < ActionController::Base
end
# TODO When should we extract file text?
def put_file
Rails.logger.warn "put file"
logger.warn "put file"
@asset.with_lock do
lock = request.headers["X-WOPI-Lock"]
if @asset.is_locked
if @asset.lock == lock
Rails.logger.warn "replacing file"
logger.warn "replacing file"
@asset.update_contents(request.body)
response.headers["X-WOPI-ItemVersion"] = @asset.version
render :nothing => true, :status => 200 and return
else
Rails.logger.warn "wrong lock used to try and modify file"
logger.warn "wrong lock used to try and modify file"
response.headers["X-WOPI-Lock"] = @asset.lock
render :nothing => true, :status => 409 and return
end
else
if !@asset.file_file_size.nil? and @asset.file_file_size==0
Rails.logger.warn "initializing empty file"
logger.warn "initializing empty file"
@asset.update_contents(request.body)
response.headers["X-WOPI-ItemVersion"] = @asset.version
render :nothing => true, :status => 200 and return
else
Rails.logger.warn "trying to modify unlocked file"
logger.warn "trying to modify unlocked file"
response.headers["X-WOPI-Lock"] = ""
render :nothing => true, :status => 409 and return
end
@ -237,7 +239,7 @@ class WopiController < ActionController::Base
if @asset.nil?
render :nothing => true, :status => 404 and return
else
Rails.logger.warn "Found asset"
logger.warn "Found asset"
step_assoc = @asset.step
result_assoc = @asset.result
@assoc = step_assoc if not step_assoc.nil?
@ -255,37 +257,44 @@ class WopiController < ActionController::Base
def authenticate_user_from_token!
wopi_token = params[:access_token]
if wopi_token.nil?
Rails.logger.warn "nil wopi token"
logger.warn "nil wopi token"
render :nothing => true, :status => 401 and return
end
@user = User.find_by_valid_wopi_token(wopi_token)
if @user.nil?
Rails.logger.warn "no user with this token found"
logger.warn "no user with this token found"
render :nothing => true, :status => 401 and return
end
Rails.logger.warn "user found by token"
logger.warn "user found by token"
#TODO check if the user can do anything with the file
end
def verify_proof!
begin
token = params[:access_token]
timestamp = request.headers["X-WOPI-TimeStamp"]
signed_proof = request.headers["X-WOPI-Proof"]
signed_proof_old = request.headers["X-WOPI-ProofOld"]
url = request.original_url.upcase
token = params[:access_token].encode('utf-8')
timestamp = request.headers['X-WOPI-TimeStamp'].to_i
signed_proof = request.headers['X-WOPI-Proof']
signed_proof_old = request.headers['X-WOPI-ProofOld']
url = request.original_url.upcase.encode('utf-8')
unless WopiDiscovery.first.verify_proof(token, timestamp, signed_proof,
signed_proof_old, url)
render :nothing => true, :status => 401 and return
if convert_to_unix_timestamp(timestamp) + 20.minutes >= Time.now
if get_discovery.verify_proof(token, timestamp, signed_proof,
signed_proof_old, url)
logger.warn 'Proof verification: successful'
else
logger.warn 'Proof verification: not verified'
render :nothing => true, :status => 500 and return
end
else
logger.warn 'Proof verification: timestamp too old; ' + timestamp.to_s
render :nothing => true, :status => 500 and return
end
rescue
Rails.logger.warn "proof verification failed"
render :nothing => true, :status => 401 and return
rescue => e
logger.warn 'Proof verification: failed; ' + e.message
render :nothing => true, :status => 500 and return
end
end
end

View file

@ -1,28 +1,38 @@
module WopiUtil
require 'open-uri'
# Used for timestamp
UNIX_EPOCH_IN_CLR_TICKS = 621355968000000000
CLR_TICKS_PER_SECOND = 10000000
DISCOVERY_TTL = 60*60*24
DISCOVERY_TTL.freeze
# For more explanation see this:
# http://stackoverflow.com/questions/11888053/
# convert-net-datetime-ticks-property-to-date-in-objective-c
def convert_to_unix_timestamp(timestamp)
Time.at((timestamp-UNIX_EPOCH_IN_CLR_TICKS)/CLR_TICKS_PER_SECOND)
end
def get_action(extension, activity)
get_discovery
action = WopiAction.find_action(extension, activity)
end
def get_discovery
discovery = WopiDiscovery.first
if discovery.nil? || discovery.expires < Time.now.to_i
initializeDiscovery(discovery)
end
action = WopiAction.find_action(extension,activity)
return discovery if discovery && discovery.expires >= Time.now.to_i
initialize_discovery(discovery)
end
private
# Currently only saves Excel, Word and PowerPoint view and edit actions
def initializeDiscovery(discovery)
def initialize_discovery(discovery)
begin
Rails.logger.warn "Initializing discovery"
unless discovery.nil?
discovery.destroy
end
discovery.destroy if discovery
@doc = Nokogiri::XML(open(ENV["WOPI_DISCOVERY_URL"]))
@ -56,15 +66,13 @@ module WopiUtil
end
end
end
discovery
rescue
Rails.logger.warn "Initialization failed"
discovery = WopiDiscovery.first
unless discovery.nil?
discovery.destroy
end
discovery.destroy if discovery
end
end
end
end

View file

@ -1,4 +1,7 @@
class WopiDiscoveryTest < ActiveSupport::TestCase
# These tests are taken from WOPI official documentation
# https://github.com/Microsoft/Office-Online-Test-Tools-and-Documentation/
# blob/master/samples/python/proof_keys/tests.py
def setup
@discovery = wopi_discoveries(:first)
end