Refactor the rest of WOPI logic from Nejc

This commit is contained in:
Jure Grabnar 2016-09-23 11:42:12 +02:00
parent c1ae4360a3
commit 5aea0fbb19
12 changed files with 247 additions and 261 deletions

View file

@ -66,31 +66,27 @@ class AssetsController < ApplicationController
end end
def edit def edit
@action_url = @asset.get_action_url(current_user,"edit",false) @action_url = @asset.get_action_url(current_user, 'edit', false)
@token = current_user.get_wopi_token @token = current_user.get_wopi_token
@ttl = (current_user.wopi_token_ttl*1000).to_s @ttl = (current_user.wopi_token_ttl * 1000).to_s
end end
def view def view
@action_url = @asset.get_action_url(current_user,"view",false) @action_url = @asset.get_action_url(current_user, 'view', false)
@token = current_user.get_wopi_token @token = current_user.get_wopi_token
@ttl = (current_user.wopi_token_ttl*1000).to_s @ttl = (current_user.wopi_token_ttl * 1000).to_s
end end
private private
def load_vars def load_vars
@asset = Asset.find_by_id(params[:id]) @asset = Asset.find_by_id(params[:id])
render_404 unless @asset
unless @asset
render_404
end
step_assoc = @asset.step step_assoc = @asset.step
result_assoc = @asset.result result_assoc = @asset.result
@assoc = step_assoc unless step_assoc.nil?
@assoc = step_assoc if not step_assoc.nil? @assoc = result_assoc unless result_assoc.nil?
@assoc = result_assoc if not result_assoc.nil?
if @assoc.class == Step if @assoc.class == Step
@protocol = @asset.step.protocol @protocol = @asset.step.protocol

View file

@ -92,7 +92,7 @@ class WopiController < ActionController::Base
logger.warn 'WOPI: lock; ' + lock.to_s logger.warn 'WOPI: lock; ' + lock.to_s
render nothing: :true, status: 404 and return if lock.nil? || lock.blank? render nothing: :true, status: 404 and return if lock.nil? || lock.blank?
@asset.with_lock do @asset.with_lock do
if @asset.is_locked if @asset.locked?
if @asset.lock == lock if @asset.lock == lock
@asset.refresh_lock @asset.refresh_lock
response.headers['X-WOPI-ItemVersion'] = @asset.version response.headers['X-WOPI-ItemVersion'] = @asset.version
@ -117,7 +117,7 @@ class WopiController < ActionController::Base
render nothing: :true, status: 400 and return render nothing: :true, status: 400 and return
end end
@asset.with_lock do @asset.with_lock do
if @asset.is_locked if @asset.locked?
if @asset.lock == old_lock if @asset.lock == old_lock
@asset.unlock @asset.unlock
@asset.lock_asset(lock) @asset.lock_asset(lock)
@ -138,9 +138,9 @@ class WopiController < ActionController::Base
lock = request.headers['X-WOPI-Lock'] lock = request.headers['X-WOPI-Lock']
render nothing: :true, status: 400 and return if lock.nil? || lock.blank? render nothing: :true, status: 400 and return if lock.nil? || lock.blank?
@asset.with_lock do @asset.with_lock do
if @asset.is_locked if @asset.locked?
logger.warn 'WOPI: current asset lock: #{@asset.lock}, logger.warn "WOPI: current asset lock: #{@asset.lock},
unlocking lock #{lock}' unlocking lock #{lock}"
if @asset.lock == lock if @asset.lock == lock
@asset.unlock @asset.unlock
response.headers['X-WOPI-ItemVersion'] = @asset.version response.headers['X-WOPI-ItemVersion'] = @asset.version
@ -161,7 +161,7 @@ class WopiController < ActionController::Base
lock = request.headers['X-WOPI-Lock'] lock = request.headers['X-WOPI-Lock']
render nothing: :true, status: 400 and return if lock.nil? || lock.blank? render nothing: :true, status: 400 and return if lock.nil? || lock.blank?
@asset.with_lock do @asset.with_lock do
if @asset.is_locked if @asset.locked?
if @asset.lock == lock if @asset.lock == lock
@asset.refresh_lock @asset.refresh_lock
response.headers['X-WOPI-ItemVersion'] = @asset.version response.headers['X-WOPI-ItemVersion'] = @asset.version
@ -180,7 +180,7 @@ class WopiController < ActionController::Base
def get_lock def get_lock
@asset.with_lock do @asset.with_lock do
if @asset.is_locked if @asset.locked?
response.headers['X-WOPI-Lock'] = @asset.lock response.headers['X-WOPI-Lock'] = @asset.lock
else else
response.headers['X-WOPI-Lock'] = '' response.headers['X-WOPI-Lock'] = ''
@ -193,7 +193,7 @@ class WopiController < ActionController::Base
def put_file def put_file
@asset.with_lock do @asset.with_lock do
lock = request.headers['X-WOPI-Lock'] lock = request.headers['X-WOPI-Lock']
if @asset.is_locked if @asset.locked?
if @asset.lock == lock if @asset.lock == lock
logger.warn 'WOPI: replacing file' logger.warn 'WOPI: replacing file'
@asset.update_contents(request.body) @asset.update_contents(request.body)
@ -263,8 +263,8 @@ class WopiController < ActionController::Base
url = request.original_url.upcase.encode('utf-8') url = request.original_url.upcase.encode('utf-8')
if convert_to_unix_timestamp(timestamp) + 20.minutes >= Time.now if convert_to_unix_timestamp(timestamp) + 20.minutes >= Time.now
if get_discovery.verify_proof(token, timestamp, signed_proof, if current_wopi_discovery.verify_proof(token, timestamp, signed_proof,
signed_proof_old, url) signed_proof_old, url)
logger.warn 'WOPI: proof verification: successful' logger.warn 'WOPI: proof verification: successful'
else else
logger.warn 'WOPI: proof verification: not verified' logger.warn 'WOPI: proof verification: not verified'

View file

@ -288,9 +288,12 @@ class Asset < ActiveRecord::Base
end end
end end
# Preserving attachments (on client-side) between failed validations (only usable for small/few files!) # Preserving attachments (on client-side) between failed validations
# Needs to be called before save method and view needs to have :file_content and :file_info hidden field # (only usable for small/few files!).
# If file is an image, it can be viewed on front-end using @preview_cached with image_tag tag # Needs to be called before save method and view needs to have
# :file_content and :file_info hidden field.
# If file is an image, it can be viewed on front-end
# using @preview_cached with image_tag tag.
def preserve(file_data) def preserve(file_data)
if file_data[:file_content].present? if file_data[:file_content].present?
restore_cached(file_data[:file_content], file_data[:file_info]) restore_cached(file_data[:file_content], file_data[:file_info])
@ -299,28 +302,31 @@ class Asset < ActiveRecord::Base
end end
def can_perform_action(action) def can_perform_action(action)
file_ext = file_file_name.split(".").last file_ext = file_file_name.split('.').last
action = get_action(file_ext,action) action = get_action(file_ext, action)
if action.nil? return false if action.nil?
return false
end
true true
end end
def get_action_url(user, action, with_tokens = true)
def get_action_url(user,action,with_tokens = true) file_ext = file_file_name.split('.').last
file_ext = file_file_name.split(".").last action = get_action(file_ext, action)
action = get_action(file_ext,action)
if !action.nil? if !action.nil?
action_url = action.urlsrc action_url = action.urlsrc
action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER&>/, "IsLicensedUser=0&") action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER&>/,
action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER>/, "IsLicensedUser=0") 'IsLicensedUser=0&')
action_url = action_url.gsub(/<.*?=.*?>/, "") action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER>/,
'IsLicensedUser=0')
action_url = action_url.gsub(/<.*?=.*?>/, '')
rest_url = Rails.application.routes.url_helpers.wopi_rest_endpoint_url(host: ENV["WOPI_ENDPOINT_URL"],id: id) rest_url = Rails.application.routes.url_helpers.wopi_rest_endpoint_url(
action_url = action_url + "WOPISrc=#{rest_url}" host: ENV['WOPI_ENDPOINT_URL'],
id: id
)
action_url += "WOPISrc=#{rest_url}"
if with_tokens if with_tokens
action_url = action_url + "&access_token=#{user.get_wopi_token}&access_token_ttl=#{(user.wopi_token_ttl*1000).to_s}" action_url + "&access_token=#{user.get_wopi_token}"\
"&access_token_ttl=#{(user.wopi_token_ttl * 1000)}"
else else
action_url action_url
end end
@ -329,57 +335,49 @@ class Asset < ActiveRecord::Base
end end
end end
#is_locked, lock_asset and refresh_lock rely on the asset being locked in the database to prevent race conditions # locked?, lock_asset and refresh_lock rely on the asset
def is_locked # being locked in the database to prevent race conditions
if lock.nil? def locked?
return false !lock.nil?
else
return true
end
end end
def lock_asset(lock_string) def lock_asset(lock_string)
self.lock = lock_string self.lock = lock_string
self.lock_ttl = Time.now.to_i + LOCK_DURATION self.lock_ttl = Time.now.to_i + LOCK_DURATION
delay(queue: :assets, run_at: LOCK_DURATION.seconds.from_now).unlock_expired delay(queue: :assets, run_at: LOCK_DURATION.seconds.from_now).unlock_expired
self.save! save!
end end
def refresh_lock def refresh_lock
self.lock_ttl = Time.now.to_i + LOCK_DURATION self.lock_ttl = Time.now.to_i + LOCK_DURATION
delay(queue: :assets, run_at: LOCK_DURATION.seconds.from_now).unlock_expired delay(queue: :assets, run_at: LOCK_DURATION.seconds.from_now).unlock_expired
self.save! save!
end end
def unlock def unlock
self.lock = nil self.lock = nil
self.lock_ttl = nil self.lock_ttl = nil
self.save! save!
end end
def unlock_expired def unlock_expired
self.with_lock do with_lock do
if !self.lock_ttl.nil? and self.lock_ttl>= Time.now.to_i if !lock_ttl.nil? && lock_ttl >= Time.now.to_i
self.lock = nil self.lock = nil
self.lock_ttl = nil self.lock_ttl = nil
self.save! save!
end end
end end
end end
def update_contents(new_file) def update_contents(new_file)
new_file.class.class_eval { attr_accessor :original_filename } new_file.class.class_eval { attr_accessor :original_filename }
new_file.original_filename = self.file_file_name new_file.original_filename = file_file_name
self.file = new_file self.file = new_file
if self.version.nil? self.version = version.nil? ? 1 : version + 1
self.version = 1 save
else
self.version = self.version + 1
end
self.save
end end
protected protected
# Checks if attachments is an image (in post processing imagemagick will # Checks if attachments is an image (in post processing imagemagick will

View file

@ -253,33 +253,28 @@ class User < ActiveRecord::Base
end end
def self.find_by_valid_wopi_token(token) def self.find_by_valid_wopi_token(token)
Rails.logger.warn "Searching by token #{token}" Rails.logger.warn "WOPI: searching by token #{token}"
user = User.where("wopi_token = ?", token).first User.where('wopi_token = ?', token).first
return user
end end
def token_valid def token_valid
if !self.wopi_token.nil? and (self.wopi_token_ttl==0 or self.wopi_token_ttl > Time.now.to_i) !wopi_token.nil? && (wopi_token_ttl.zero? || wopi_token_ttl > Time.now.to_i)
return true
else
return false
end
end end
def get_wopi_token def get_wopi_token
unless token_valid unless token_valid
# if current token is not valid generate a new one with a one day TTL # If current token is not valid generate a new one with a one day TTL
self.wopi_token = Devise.friendly_token(20) self.wopi_token = Devise.friendly_token(20)
# WOPI uses millisecond TTLs # WOPI uses millisecond TTLs
self.wopi_token_ttl = Time.now.to_i + 60*60*24 self.wopi_token_ttl = Time.now.to_i + 1.days
self.save save
Rails.logger.warn("Generating new token #{self.wopi_token}") Rails.logger.warn("Generating new token #{wopi_token}")
end end
Rails.logger.warn("Returning token #{self.wopi_token}") Rails.logger.warn("Returning token #{wopi_token}")
self.wopi_token wopi_token
end end
protected protected
def time_zone_check def time_zone_check
if time_zone.nil? or ActiveSupport::TimeZone.new(time_zone).nil? if time_zone.nil? or ActiveSupport::TimeZone.new(time_zone).nil?

View file

@ -1,12 +1,9 @@
class WopiAction < ActiveRecord::Base class WopiAction < ActiveRecord::Base
belongs_to :wopi_app, foreign_key: 'wopi_app_id', class_name: 'WopiApp'
validates :action, :extension, :urlsrc, :wopi_app, presence: true
belongs_to :wopi_app, :foreign_key => 'wopi_app_id', :class_name => 'WopiApp' def self.find_action(extension, activity)
validates :action,:extension,:urlsrc,:wopi_app, presence: true WopiAction.distinct
.where('extension = ? and action = ?', extension, activity).first
end
def self.find_action(extension,activity) end
WopiAction.distinct
.where("extension = ? and action = ?",extension,activity).first
end
end

View file

@ -1,8 +1,10 @@
class WopiApp < ActiveRecord::Base class WopiApp < ActiveRecord::Base
belongs_to :wopi_discovery,
belongs_to :wopi_discovery, :foreign_key => 'wopi_discovery_id', :class_name => 'WopiDiscovery' foreign_key: 'wopi_discovery_id',
has_many :wopi_actions, class_name: 'WopiAction', foreign_key: 'wopi_app_id', :dependent => :destroy class_name: 'WopiDiscovery'
has_many :wopi_actions,
validates :name, :icon, :wopi_discovery, presence: true class_name: 'WopiAction',
foreign_key: 'wopi_app_id',
end dependent: :destroy
validates :name, :icon, :wopi_discovery, presence: true
end

View file

@ -1,45 +1,53 @@
class WopiDiscovery < ActiveRecord::Base class WopiDiscovery < ActiveRecord::Base
require 'base64' require 'base64'
has_many :wopi_apps, class_name: 'WopiApp', foreign_key: 'wopi_discovery_id', :dependent => :destroy has_many :wopi_apps,
validates :expires, :proof_key_mod, :proof_key_exp, :proof_key_old_mod, :proof_key_old_exp, presence: true class_name: 'WopiApp',
foreign_key: 'wopi_discovery_id',
dependent: :destroy
validates :expires,
:proof_key_mod,
:proof_key_exp,
:proof_key_old_mod,
:proof_key_old_exp,
presence: true
# Verifies if proof from headers, X-WOPI-Proof/X-WOPI-OldProof was encrypted # Verifies if proof from headers, X-WOPI-Proof/X-WOPI-OldProof was encrypted
# with this discovery public key (two key possible old/new) # with this discovery public key (two key possible old/new)
def verify_proof(token, timestamp, signed_proof, signed_proof_old, url) def verify_proof(token, timestamp, signed_proof, signed_proof_old, url)
token_length = [token.length].pack('>N').bytes token_length = [token.length].pack('>N').bytes
timestamp_bytes = [timestamp.to_i].pack('>Q').bytes.reverse timestamp_bytes = [timestamp.to_i].pack('>Q').bytes.reverse
timestamp_length = [timestamp_bytes.length].pack('>N').bytes timestamp_length = [timestamp_bytes.length].pack('>N').bytes
url_length = [url.length].pack('>N').bytes url_length = [url.length].pack('>N').bytes
expected_proof = token_length + token.bytes + expected_proof = token_length + token.bytes +
url_length + url.upcase.bytes + url_length + url.upcase.bytes +
timestamp_length + timestamp_bytes timestamp_length + timestamp_bytes
key = generate_key(proof_key_mod, proof_key_exp) key = generate_key(proof_key_mod, proof_key_exp)
old_key = generate_key(proof_key_old_mod, proof_key_old_exp) old_key = generate_key(proof_key_old_mod, proof_key_old_exp)
# Try all possible combiniations # Try all possible combiniations
try_verification(expected_proof, signed_proof, key) || try_verification(expected_proof, signed_proof, key) ||
try_verification(expected_proof, signed_proof_old, key) || try_verification(expected_proof, signed_proof_old, key) ||
try_verification(expected_proof, signed_proof, old_key) try_verification(expected_proof, signed_proof, old_key)
end end
# Generates a public key from given modulus and exponent # Generates a public key from given modulus and exponent
def generate_key(modulus, exponent) def generate_key(modulus, exponent)
mod = Base64.decode64(modulus).unpack('H*').first.to_i(16) mod = Base64.decode64(modulus).unpack('H*').first.to_i(16)
exp = Base64.decode64(exponent).unpack('H*').first.to_i(16) exp = Base64.decode64(exponent).unpack('H*').first.to_i(16)
seq = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::Integer.new(mod), seq = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::Integer.new(mod),
OpenSSL::ASN1::Integer.new(exp)]) OpenSSL::ASN1::Integer.new(exp)])
OpenSSL::PKey::RSA.new(seq.to_der) OpenSSL::PKey::RSA.new(seq.to_der)
end end
# Verify if decrypting signed_proof with public_key equals to expected_proof # Verify if decrypting signed_proof with public_key equals to expected_proof
def try_verification(expected_proof, signed_proof_b64, public_key) def try_verification(expected_proof, signed_proof_b64, public_key)
signed_proof = Base64.decode64(signed_proof_b64) signed_proof = Base64.decode64(signed_proof_b64)
public_key.verify(OpenSSL::Digest::SHA256.new, signed_proof, public_key.verify(OpenSSL::Digest::SHA256.new, signed_proof,
expected_proof.pack('c*')) expected_proof.pack('c*'))
end end
end end

View file

@ -5,22 +5,22 @@ module WopiUtil
UNIX_EPOCH_IN_CLR_TICKS = 621355968000000000 UNIX_EPOCH_IN_CLR_TICKS = 621355968000000000
CLR_TICKS_PER_SECOND = 10000000 CLR_TICKS_PER_SECOND = 10000000
DISCOVERY_TTL = 60*60*24 DISCOVERY_TTL = 1.days
DISCOVERY_TTL.freeze DISCOVERY_TTL.freeze
# For more explanation see this: # For more explanation see this:
# http://stackoverflow.com/questions/11888053/ # http://stackoverflow.com/questions/11888053/
# convert-net-datetime-ticks-property-to-date-in-objective-c # convert-net-datetime-ticks-property-to-date-in-objective-c
def convert_to_unix_timestamp(timestamp) def convert_to_unix_timestamp(timestamp)
Time.at((timestamp-UNIX_EPOCH_IN_CLR_TICKS)/CLR_TICKS_PER_SECOND) Time.at((timestamp - UNIX_EPOCH_IN_CLR_TICKS) / CLR_TICKS_PER_SECOND)
end end
def get_action(extension, activity) def get_action(extension, activity)
get_discovery current_wopi_discovery
action = WopiAction.find_action(extension, activity) WopiAction.find_action(extension, activity)
end end
def get_discovery def current_wopi_discovery
discovery = WopiDiscovery.first discovery = WopiDiscovery.first
return discovery if discovery && discovery.expires >= Time.now.to_i return discovery if discovery && discovery.expires >= Time.now.to_i
initialize_discovery(discovery) initialize_discovery(discovery)
@ -30,49 +30,44 @@ module WopiUtil
# Currently only saves Excel, Word and PowerPoint view and edit actions # Currently only saves Excel, Word and PowerPoint view and edit actions
def initialize_discovery(discovery) def initialize_discovery(discovery)
begin Rails.logger.warn 'Initializing discovery'
Rails.logger.warn "Initializing discovery" discovery.destroy if discovery
discovery.destroy if discovery
@doc = Nokogiri::XML(open(ENV["WOPI_DISCOVERY_URL"])) @doc = Nokogiri::XML(open(ENV['WOPI_DISCOVERY_URL']))
discovery = WopiDiscovery.new discovery = WopiDiscovery.new
discovery.expires = Time.now.to_i + DISCOVERY_TTL discovery.expires = Time.now.to_i + DISCOVERY_TTL
key = @doc.xpath("//proof-key") key = @doc.xpath('//proof-key')
discovery.proof_key_mod = key.xpath("@modulus").first.value discovery.proof_key_mod = key.xpath('@modulus').first.value
discovery.proof_key_exp = key.xpath("@exponent").first.value discovery.proof_key_exp = key.xpath('@exponent').first.value
discovery.proof_key_old_mod = key.xpath("@oldmodulus").first.value discovery.proof_key_old_mod = key.xpath('@oldmodulus').first.value
discovery.proof_key_old_exp = key.xpath("@oldexponent").first.value discovery.proof_key_old_exp = key.xpath('@oldexponent').first.value
discovery.save! discovery.save!
@doc.xpath("//app").each do |app| @doc.xpath('//app').each do |app|
app_name = app.xpath("@name").first.value app_name = app.xpath('@name').first.value
if ["Excel","Word","PowerPoint","WopiTest"].include?(app_name) next unless %w(Excel Word PowerPoint WopiTest).include?(app_name)
wopi_app = WopiApp.new
wopi_app.name = app.xpath("@name").first.value wopi_app = WopiApp.new
wopi_app.icon = app.xpath("@favIconUrl").first.value wopi_app.name = app.xpath('@name').first.value
wopi_app.wopi_discovery_id=discovery.id wopi_app.icon = app.xpath('@favIconUrl').first.value
wopi_app.save! wopi_app.wopi_discovery_id = discovery.id
app.xpath("action").each do |action| wopi_app.save!
name = action.xpath("@name").first.value app.xpath('action').each do |action|
if ["view","edit","wopitest"].include?(name) name = action.xpath('@name').first.value
wopi_action = WopiAction.new next unless %w(view edit wopitest).include?(name)
wopi_action.action = name wopi_action = WopiAction.new
wopi_action.extension = action.xpath("@ext").first.value wopi_action.action = name
wopi_action.urlsrc = action.xpath("@urlsrc").first.value wopi_action.extension = action.xpath('@ext').first.value
wopi_action.wopi_app_id = wopi_app.id wopi_action.urlsrc = action.xpath('@urlsrc').first.value
wopi_action.save! wopi_action.wopi_app_id = wopi_app.id
end wopi_action.save!
end
end
end end
discovery
rescue
Rails.logger.warn "Initialization failed"
discovery = WopiDiscovery.first
discovery.destroy if discovery
end end
discovery
rescue
Rails.logger.warn 'Initialization failed'
discovery = WopiDiscovery.first
discovery.destroy if discovery
end end
end end

View file

@ -1,6 +1,6 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<!-- Enable IE Standards mode --> <!-- Enable IE Standards mode -->
@ -9,56 +9,56 @@
<title></title> <title></title>
<meta name="description" content=""> <meta name="description" content="">
<meta name="viewport" <meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<link rel="shortcut icon" <link rel="shortcut icon"
href="" /> href="" />
<style type="text/css"> <style type="text/css">
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow:hidden; overflow:hidden;
-ms-content-zooming: none; -ms-content-zooming: none;
} }
#office_frame { #office_frame {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
margin: 0; margin: 0;
border: none; border: none;
display: block; display: block;
} }
</style> </style>
</head> </head>
<body> <body>
<form id="office_form" name="office_form" target="office_frame" <form id="office_form" name="office_form" target="office_frame"
action=<%=@action_url %> action=<%=@action_url %>
method="post"> method="post">
<input name="access_token" value=<%= @token%> type="hidden"/> <input name="access_token" value=<%= @token%> type="hidden"/>
<input name="access_token_ttl" value= <%= @ttl %> type="hidden"/> <input name="access_token_ttl" value= <%= @ttl %> type="hidden"/>
</form> </form>
<span id="frameholder"></span> <span id="frameholder"></span>
<script type="text/javascript"> <script type="text/javascript">
var frameholder = document.getElementById('frameholder'); var frameholder = document.getElementById('frameholder');
var office_frame = document.createElement('iframe'); var office_frame = document.createElement('iframe');
office_frame.name = 'office_frame'; office_frame.name = 'office_frame';
office_frame.id ='office_frame'; office_frame.id ='office_frame';
// The title should be set for accessibility // The title should be set for accessibility
office_frame.title = 'Office Online Frame'; office_frame.title = 'Office Online Frame';
// This attribute allows true fullscreen mode in slideshow view // This attribute allows true fullscreen mode in slideshow view
// when using PowerPoint Online's 'view' action. // when using PowerPoint Online's 'view' action.
office_frame.setAttribute('allowfullscreen', 'true'); office_frame.setAttribute('allowfullscreen', 'true');
frameholder.appendChild(office_frame); frameholder.appendChild(office_frame);
document.getElementById('office_form').submit(); document.getElementById('office_form').submit();
</script> </script>
</body> </body>
</html> </html>

View file

@ -1,6 +1,6 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<!-- Enable IE Standards mode --> <!-- Enable IE Standards mode -->
@ -9,56 +9,56 @@
<title></title> <title></title>
<meta name="description" content=""> <meta name="description" content="">
<meta name="viewport" <meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<link rel="shortcut icon" <link rel="shortcut icon"
href="" /> href="" />
<style type="text/css"> <style type="text/css">
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow:hidden; overflow:hidden;
-ms-content-zooming: none; -ms-content-zooming: none;
} }
#office_frame { #office_frame {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
margin: 0; margin: 0;
border: none; border: none;
display: block; display: block;
} }
</style> </style>
</head> </head>
<body> <body>
<form id="office_form" name="office_form" target="office_frame" <form id="office_form" name="office_form" target="office_frame"
action=<%=@action_url %> action=<%=@action_url %>
method="post"> method="post">
<input name="access_token" value=<%= @token%> type="hidden"/> <input name="access_token" value=<%= @token%> type="hidden"/>
<input name="access_token_ttl" value= <%= @ttl %> type="hidden"/> <input name="access_token_ttl" value= <%= @ttl %> type="hidden"/>
</form> </form>
<span id="frameholder"></span> <span id="frameholder"></span>
<script type="text/javascript"> <script type="text/javascript">
var frameholder = document.getElementById('frameholder'); var frameholder = document.getElementById('frameholder');
var office_frame = document.createElement('iframe'); var office_frame = document.createElement('iframe');
office_frame.name = 'office_frame'; office_frame.name = 'office_frame';
office_frame.id ='office_frame'; office_frame.id ='office_frame';
// The title should be set for accessibility // The title should be set for accessibility
office_frame.title = 'Office Online Frame'; office_frame.title = 'Office Online Frame';
// This attribute allows true fullscreen mode in slideshow view // This attribute allows true fullscreen mode in slideshow view
// when using PowerPoint Online's 'view' action. // when using PowerPoint Online's 'view' action.
office_frame.setAttribute('allowfullscreen', 'true'); office_frame.setAttribute('allowfullscreen', 'true');
frameholder.appendChild(office_frame); frameholder.appendChild(office_frame);
document.getElementById('office_form').submit(); document.getElementById('office_form').submit();
</script> </script>
</body> </body>
</html> </html>

View file

@ -30,13 +30,10 @@ module Scinote
"[#{datetime}] #{severity}: #{msg}\n" "[#{datetime}] #{severity}: #{msg}\n"
end end
#config.action_dispatch.default_headers = {
#'X-WOPI-Lock' => "",
#'Random-header' => "with value",
#'Random-non-special-header' => "a"
#}
# Paperclip spoof checking # Paperclip spoof checking
Paperclip.options[:content_type_mappings] = {:csv => "text/plain", wopitest: ['text/plain', 'inode/x-empty'] } Paperclip.options[:content_type_mappings] = {
csv: 'text/plain',
wopitest: ['text/plain', 'inode/x-empty']
}
end end
end end

View file

@ -1,10 +1,9 @@
class AddWopi< ActiveRecord::Migration class AddWopi < ActiveRecord::Migration
def up def up
add_column :users, :wopi_token, :string add_column :users, :wopi_token, :string
add_column :users, :wopi_token_ttl, :integer add_column :users, :wopi_token_ttl, :integer
add_column :assets, :lock, :string, :limit => 1024 add_column :assets, :lock, :string, limit: 1024
add_column :assets, :lock_ttl, :integer add_column :assets, :lock_ttl, :integer
add_column :assets, :version, :integer, default: 1 add_column :assets, :version, :integer, default: 1
@ -32,8 +31,7 @@ class AddWopi< ActiveRecord::Migration
add_foreign_key :wopi_actions, :wopi_apps, column: :wopi_app_id add_foreign_key :wopi_actions, :wopi_apps, column: :wopi_app_id
add_foreign_key :wopi_apps, :wopi_discoveries, column: :wopi_discovery_id add_foreign_key :wopi_apps, :wopi_discoveries, column: :wopi_discovery_id
add_index :wopi_actions, [:extension,:action] add_index :wopi_actions, [:extension, :action]
end end
def down def down