Refactor WopiController

This commit is contained in:
Jure Grabnar 2016-09-23 10:27:30 +02:00
parent 0c9292e4fc
commit c1ae4360a3
2 changed files with 178 additions and 199 deletions

View file

@ -1,251 +1,232 @@
class WopiController < ActionController::Base
include WopiUtil
before_action :load_vars,:authenticate_user_from_token!
before_action :load_vars, :authenticate_user_from_token!
before_action :verify_proof!
def get_file_endpoint
logger.warn "get_file called"
#Only used for checkfileinfo
# Only used for checkfileinfo
def file_get_endpoint
check_file_info
end
def get_file_contents_endpoint
logger.warn "get_file_contents called"
#Only used for getfile
get_file
def file_contents_get_endpoint
# get_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 post_file_endpoint
logger.warn "post_file called"
override = request.headers["X-WOPI-Override"]
override = request.headers['X-WOPI-Override']
case override
when "GET_LOCK"
get_lock
when "PUT_RELATIVE"
put_relative
when "LOCK"
old_lock = request.headers["X-WOPI-OldLock"]
if old_lock.nil?
lock
else
unlock_and_relock
end
when "UNLOCK"
unlock
when "REFRESH_LOCK"
refresh_lock
when "GET_SHARE_URL"
render :nothing => true, :status => 501 and return
when 'GET_LOCK'
get_lock
when 'PUT_RELATIVE'
put_relative
when 'LOCK'
old_lock = request.headers['X-WOPI-OldLock']
if old_lock.nil?
lock
else
render :nothing => true, :status => 404 and return
unlock_and_relock
end
when 'UNLOCK'
unlock
when 'REFRESH_LOCK'
refresh_lock
when 'GET_SHARE_URL'
render nothing: :true, status: 501 and return
else
render nothing: :true, status: 404 and return
end
end
def post_file_contents_endpoint
logger.warn "post_file_contents called"
#Only used for putfile
# Only used for putfile
def file_contents_post_endpoint
logger.warn 'WOPI: post_file_contents called'
put_file
end
def check_file_info
logger.warn "Check file info started"
msg = { :BaseFileName => @asset.file_file_name,
:OwnerId => @asset.created_by_id.to_s,
:Size => @asset.file_file_size,
:UserId => @user.id,
:Version => @asset.version,
:SupportsExtendedLockLength => true,
:SupportsGetLock => true,
:SupportsLocks => true,
:SupportsUpdate => true,
#Setting all users to business until we figure out which should NOT be business
:LicenseCheckForEditIsEnabled => true,
:UserFriendlyName => @user.name,
#TODO Check user permisisons
:ReadOnly => false,
:UserCanNotWriteRelative => true,
:UserCanWrite => true,
#TODO decide what to put here
:CloseUrl => "https://scinote-preview.herokuapp.com",
:DownloadUrl => url_for(controller: 'assets',action: 'download',id: @asset.id),
:HostEditUrl => url_for(controller: 'assets',action: 'edit',id: @asset.id),
:HostViewUrl => url_for(controller: 'assets',action: 'view',id: @asset.id)
#TODO breadcrumbs?
#:FileExtension
}
response.headers['X-WOPI-HostEndpoint'] = ENV["WOPI_ENDPOINT_URL"]
response.headers['X-WOPI-MachineName'] = ENV["WOPI_ENDPOINT_URL"]
response.headers['X-WOPI-ServerVersion'] = APP_VERSION
render json:msg and return
end
def get_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'
msg = {
BaseFileName: @asset.file_file_name,
OwnerId: @asset.created_by_id.to_s,
Size: @asset.file_file_size,
UserId: @user.id,
Version: @asset.version,
SupportsExtendedLockLength: true,
SupportsGetLock: true,
SupportsLocks: true,
SupportsUpdate: true,
# Setting all users to business until we figure out
# which should NOT be business
LicenseCheckForEditIsEnabled: true,
UserFriendlyName: @user.name,
# TODO: Check user permisisons
ReadOnly: false,
UserCanNotWriteRelative: true,
UserCanWrite: true,
# TODO: decide what to put here
CloseUrl: 'https://scinote-preview.herokuapp.com',
DownloadUrl: url_for(controller: 'assets', action: 'download',
id: @asset.id),
HostEditUrl: url_for(controller: 'assets', action: 'edit',
id: @asset.id),
HostViewUrl: url_for(controller: 'assets', action: 'view',
id: @asset.id)
# TODO: breadcrumbs?
#:FileExtension
}
response.headers['X-WOPI-HostEndpoint'] = ENV['WOPI_ENDPOINT_URL']
response.headers['X-WOPI-MachineName'] = ENV['WOPI_ENDPOINT_URL']
response.headers['X-WOPI-ServerVersion'] = APP_VERSION
render json: msg and return
end
def put_relative
logger.warn "put relative"
render :nothing => true, :status => 501 and return
render nothing: :true, status: 501 and return
end
def lock
logger.warn "lock"
lock = request.headers["X-WOPI-Lock"]
if lock.nil? || lock.blank?
render :nothing => true, :status => 400 and return
end
lock = request.headers['X-WOPI-Lock']
logger.warn 'WOPI: lock; ' + lock.to_s
render nothing: :true, status: 404 and return if lock.nil? || lock.blank?
@asset.with_lock do
if @asset.is_locked
if @asset.lock == lock
@asset.refresh_lock
response.headers["X-WOPI-ItemVersion"] = @asset.version
render :nothing => true, :status => 200 and return
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
else
response.headers["X-WOPI-Lock"] = @asset.lock
render :nothing => true, :status => 409 and return
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
end
else
@asset.lock_asset(lock)
response.headers["X-WOPI-ItemVersion"] = @asset.version
render :nothing => true, :status => 200 and return
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
end
end
end
def unlock_and_relock
logger.warn "lock and relock"
lock = request.headers["X-WOPI-Lock"]
old_lock = request.headers["X-WOPI-OldLock"]
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?
render :nothing => true, :status => 400 and return
render nothing: :true, status: 400 and return
end
@asset.with_lock do
if @asset.is_locked
if @asset.lock == old_lock
@asset.unlock
@asset.lock_asset(lock)
response.headers["X-WOPI-ItemVersion"] = @asset.version
render :nothing => true, :status => 200 and return
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
else
response.headers["X-WOPI-Lock"] = @asset.lock
render :nothing => true, :status => 409 and return
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
end
else
response.headers["X-WOPI-Lock"] = ""
render :nothing => true, :status => 409 and return
response.headers['X-WOPI-Lock'] = ''
render nothing: :true, status: 409 and return
end
end
end
def unlock
logger.warn "unlock"
lock = request.headers["X-WOPI-Lock"]
if lock.nil? || lock.blank?
render :nothing => true, :status => 400 and return
end
lock = request.headers['X-WOPI-Lock']
render nothing: :true, status: 400 and return if lock.nil? || lock.blank?
@asset.with_lock do
if @asset.is_locked
logger.warn "Current asset lock: #{@asset.lock}, unlocking lock #{lock}"
logger.warn 'WOPI: current asset lock: #{@asset.lock},
unlocking lock #{lock}'
if @asset.lock == lock
@asset.unlock
response.headers["X-WOPI-ItemVersion"] = @asset.version
render :nothing => true, :status => 200 and return
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
else
response.headers["X-WOPI-Lock"] = @asset.lock
render :nothing => true, :status => 409 and return
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
end
else
logger.warn "Tried to unlock non-locked file"
response.headers["X-WOPI-Lock"] = " "
render :nothing => true, :status => 409 and return
logger.warn 'WOPI: tried to unlock non-locked file'
response.headers['X-WOPI-Lock'] = ' '
render nothing: :true, status: 409 and return
end
end
end
def refresh_lock
logger.warn "refresh lock"
lock = request.headers["X-WOPI-Lock"]
if lock.nil? || lock.blank?
render :nothing => true, :status => 400 and return
end
lock = request.headers['X-WOPI-Lock']
render nothing: :true, status: 400 and return if lock.nil? || lock.blank?
@asset.with_lock do
if @asset.is_locked
if @asset.lock == lock
@asset.refresh_lock
response.headers["X-WOPI-ItemVersion"] = @asset.version
response.headers["X-WOPI-ItemVersion"] = @asset.version
render :nothing => true, :status => 200 and return
response.headers['X-WOPI-ItemVersion'] = @asset.version
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
else
response.headers["X-WOPI-Lock"] = @asset.lock
render :nothing => true, :status => 409 and return
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
end
else
response.headers["X-WOPI-Lock"] = ""
render :nothing => true, :status => 409 and return
response.headers['X-WOPI-Lock'] = ''
render nothing: :true, status: 409 and return
end
end
end
def get_lock
logger.warn "get lock"
@asset.with_lock do
if @asset.is_locked
response.headers["X-WOPI-Lock"] = @asset.lock
render :nothing => true, :status => 200 and return
response.headers['X-WOPI-Lock'] = @asset.lock
else
response.headers["X-WOPI-Lock"] = ""
render :nothing => true, :status => 200 and return
end
end
end
# TODO When should we extract file text?
def put_file
logger.warn "put file"
@asset.with_lock do
lock = request.headers["X-WOPI-Lock"]
if @asset.is_locked
if @asset.lock == lock
logger.warn "replacing file"
@asset.update_contents(request.body)
response.headers["X-WOPI-ItemVersion"] = @asset.version
render :nothing => true, :status => 200 and return
else
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
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
logger.warn "trying to modify unlocked file"
response.headers["X-WOPI-Lock"] = ""
render :nothing => true, :status => 409 and return
end
response.headers['X-WOPI-Lock'] = ''
end
render nothing: :true, status: 200 and return
end
end
# TODO: When should we extract file text?
def put_file
@asset.with_lock do
lock = request.headers['X-WOPI-Lock']
if @asset.is_locked
if @asset.lock == lock
logger.warn 'WOPI: replacing file'
@asset.update_contents(request.body)
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
else
logger.warn 'WOPI: wrong lock used to try and modify file'
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
end
elsif !@asset.file_file_size.nil? && @asset.file_file_size.zero?
logger.warn 'WOPI: initializing empty file'
@asset.update_contents(request.body)
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
else
logger.warn 'WOPI: trying to modify unlocked file'
response.headers['X-WOPI-Lock'] = ''
render nothing: :true, status: 409 and return
end
end
end
def load_vars
@asset = Asset.find_by_id(params[:id])
if @asset.nil?
render :nothing => true, :status => 404 and return
render nothing: :true, status: 404 and return
else
logger.warn "Found asset"
logger.warn 'Found asset'
step_assoc = @asset.step
result_assoc = @asset.result
@assoc = step_assoc if not step_assoc.nil?
@assoc = result_assoc if not result_assoc.nil?
@assoc = step_assoc unless step_assoc.nil?
@assoc = result_assoc unless result_assoc.nil?
if @assoc.class == Step
@protocol = @asset.step.protocol
@ -256,47 +237,46 @@ class WopiController < ActionController::Base
end
private
def authenticate_user_from_token!
wopi_token = params[:access_token]
if wopi_token.nil?
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?
logger.warn "no user with this token found"
render :nothing => true, :status => 401 and return
end
logger.warn "user found by token"
#TODO check if the user can do anything with the file
def authenticate_user_from_token!
wopi_token = params[:access_token]
if wopi_token.nil?
logger.warn 'WOPI: nil wopi token'
render nothing: :true, status: 401 and return
end
def verify_proof!
begin
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')
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 => e
logger.warn 'Proof verification: failed; ' + e.message
render :nothing => true, :status => 500 and return
end
@user = User.find_by_valid_wopi_token(wopi_token)
if @user.nil?
logger.warn 'WOPI: no user with this token found'
render nothing: :true, status: 401 and return
end
logger.warn 'WOPI: user found by token'
# TODO: check if the user can do anything with the file
end
def verify_proof!
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')
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 'WOPI: proof verification: successful'
else
logger.warn 'WOPI: proof verification: not verified'
render nothing: :true, status: 500 and return
end
else
logger.warn 'WOPI: proof verification: timestamp too old; ' +
timestamp.to_s
render nothing: :true, status: 500 and return
end
rescue => e
logger.warn 'WOPI: proof verification: failed; ' + e.message
render nothing: :true, status: 500 and return
end
end

View file

@ -267,10 +267,9 @@ Rails.application.routes.draw do
end
# Office integration
get "wopi/files/:id/contents", to: "wopi#get_file_contents_endpoint"
post "wopi/files/:id/contents", to: "wopi#post_file_contents_endpoint"
get "wopi/files/:id", to: "wopi#get_file_endpoint", as: 'wopi_rest_endpoint'
post "wopi/files/:id", to: "wopi#post_file_endpoint"
get 'wopi/files/:id/contents', to: 'wopi#file_contents_get_endpoint'
post 'wopi/files/:id/contents', to: 'wopi#file_contents_post_endpoint'
get 'wopi/files/:id', to: 'wopi#file_get_endpoint', as: 'wopi_rest_endpoint'
post 'wopi/files/:id', to: 'wopi#post_file_endpoint'
end