Compare commits
2 Commits
dependabot
...
acl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
944668ffcb | ||
|
|
2ce668b9ea |
@@ -24,6 +24,7 @@ require 'calligraphy/web_dav_request/propfind'
|
|||||||
require 'calligraphy/web_dav_request/proppatch'
|
require 'calligraphy/web_dav_request/proppatch'
|
||||||
require 'calligraphy/web_dav_request/put'
|
require 'calligraphy/web_dav_request/put'
|
||||||
require 'calligraphy/web_dav_request/unlock'
|
require 'calligraphy/web_dav_request/unlock'
|
||||||
|
require 'calligraphy/web_dav_request/acl'
|
||||||
|
|
||||||
#:nodoc:
|
#:nodoc:
|
||||||
module Calligraphy
|
module Calligraphy
|
||||||
@@ -43,7 +44,7 @@ module Calligraphy
|
|||||||
mattr_accessor :allowed_http_methods
|
mattr_accessor :allowed_http_methods
|
||||||
@@allowed_http_methods = %w[
|
@@allowed_http_methods = %w[
|
||||||
options get put delete copy move
|
options get put delete copy move
|
||||||
mkcol propfind proppatch lock unlock
|
mkcol propfind proppatch lock unlock acl
|
||||||
]
|
]
|
||||||
|
|
||||||
# Proc responsible for returning the user's password, API key,
|
# Proc responsible for returning the user's password, API key,
|
||||||
@@ -70,7 +71,7 @@ module Calligraphy
|
|||||||
mattr_accessor :web_dav_actions
|
mattr_accessor :web_dav_actions
|
||||||
@@web_dav_actions = %i[
|
@@web_dav_actions = %i[
|
||||||
options get put delete copy move
|
options get put delete copy move
|
||||||
mkcol propfind proppatch lock unlock
|
mkcol propfind proppatch lock unlock acl
|
||||||
]
|
]
|
||||||
|
|
||||||
# Default way to set up Calligraphy.
|
# Default way to set up Calligraphy.
|
||||||
|
|||||||
15
lib/calligraphy/acl_utils.rb
Normal file
15
lib/calligraphy/acl_utils.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Calligraphy
|
||||||
|
module AclUtils
|
||||||
|
def parse_acl(xml)
|
||||||
|
[].tap do |ace|
|
||||||
|
xml.each do |node|
|
||||||
|
next unless node.is_a? Nokogiri::XML::Element
|
||||||
|
|
||||||
|
ace << node
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -5,6 +5,13 @@ module ActionDispatch
|
|||||||
class Mapper
|
class Mapper
|
||||||
#:nodoc:
|
#:nodoc:
|
||||||
module HttpHelpers
|
module HttpHelpers
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP ACL.
|
||||||
|
# acl 'bacon', to: 'food#bacon'
|
||||||
|
def acl(*args, &block)
|
||||||
|
args = web_dav_args args
|
||||||
|
map_method :acl, args, &block
|
||||||
|
end
|
||||||
|
|
||||||
# Define a Calligraphy route that only recognizes HTTP COPY.
|
# Define a Calligraphy route that only recognizes HTTP COPY.
|
||||||
# copy 'bacon', to: 'food#bacon'
|
# copy 'bacon', to: 'food#bacon'
|
||||||
def copy(*args, &block)
|
def copy(*args, &block)
|
||||||
@@ -137,6 +144,7 @@ module ActionDispatch
|
|||||||
# PROPPATCH /photos/*resource
|
# PROPPATCH /photos/*resource
|
||||||
# LOCK /photos/*resource
|
# LOCK /photos/*resource
|
||||||
# UNLOCK /photos/*resource
|
# UNLOCK /photos/*resource
|
||||||
|
# ACL /photos/*resource
|
||||||
def calligraphy_resource(*resources, &block)
|
def calligraphy_resource(*resources, &block)
|
||||||
options = resources.extract_options!.dup
|
options = resources.extract_options!.dup
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ module Calligraphy
|
|||||||
def unlock
|
def unlock
|
||||||
Calligraphy::Unlock.new(web_dav_request).execute
|
Calligraphy::Unlock.new(web_dav_request).execute
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def acl
|
||||||
|
Calligraphy::Acl.new(web_dav_request).execute
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -596,11 +596,6 @@ module Calligraphy
|
|||||||
prop
|
prop
|
||||||
end
|
end
|
||||||
|
|
||||||
# def include(prop)
|
|
||||||
# # TODO: Implement
|
|
||||||
# prop
|
|
||||||
# end
|
|
||||||
|
|
||||||
def lockdiscovery(prop)
|
def lockdiscovery(prop)
|
||||||
prop.content = fetch_lock_info
|
prop.content = fetch_lock_info
|
||||||
prop
|
prop
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ module Calligraphy
|
|||||||
# Used in OPTIONS requests.
|
# Used in OPTIONS requests.
|
||||||
def dav_compliance
|
def dav_compliance
|
||||||
compliance_classes = %w[1 2 3]
|
compliance_classes = %w[1 2 3]
|
||||||
|
compliance_classes.push 'access-control' if enable_access_control?
|
||||||
compliance_classes.push 'extended-mkcol' if enable_extended_mkcol?
|
compliance_classes.push 'extended-mkcol' if enable_extended_mkcol?
|
||||||
|
|
||||||
compliance_classes.join ', '
|
compliance_classes.join ', '
|
||||||
@@ -84,6 +85,12 @@ module Calligraphy
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Responsible for returning a boolean indicating whether the resource
|
||||||
|
# supports Access Control Protocol (see RFC3744).
|
||||||
|
def enable_access_control?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
# Responsible for returning a boolean indicating whether the resource
|
# Responsible for returning a boolean indicating whether the resource
|
||||||
# supports Extended MKCOL (see RFC5689).
|
# supports Extended MKCOL (see RFC5689).
|
||||||
def enable_extended_mkcol?
|
def enable_extended_mkcol?
|
||||||
|
|||||||
111
lib/calligraphy/web_dav_request/acl.rb
Normal file
111
lib/calligraphy/web_dav_request/acl.rb
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Calligraphy
|
||||||
|
# TODO: CHANGE DESCRIPTIONS
|
||||||
|
# Responsible for processing instructions specified in the request body
|
||||||
|
# to set and/or remove properties defined on the resource.
|
||||||
|
class Acl < WebDavRequest
|
||||||
|
include Calligraphy::XML::Utils
|
||||||
|
# include Calligraphy::AclUtils
|
||||||
|
|
||||||
|
# Responsible for evaluating preconditions for the WebDAV request.
|
||||||
|
def preconditions
|
||||||
|
# conflict_preconditions
|
||||||
|
# forbidden_preconditions
|
||||||
|
end
|
||||||
|
|
||||||
|
# Executes the WebDAV request for a particular resource.
|
||||||
|
def execute
|
||||||
|
return :locked if @resource.locked_to_user? @headers
|
||||||
|
|
||||||
|
# The `acl` tag contains the request to modify the access control list
|
||||||
|
# of a resource.
|
||||||
|
xml = xml_for body: body, node: 'acl'
|
||||||
|
return :bad_request if xml == :bad_request
|
||||||
|
|
||||||
|
ace = search_xml_for body: body, search: 'ace'
|
||||||
|
|
||||||
|
binding.pry
|
||||||
|
@resource.acl ace
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Array with compact and first?
|
||||||
|
def conflict_preconditions
|
||||||
|
[
|
||||||
|
no_ace_conflict,
|
||||||
|
no_protected_ace_conflict,
|
||||||
|
no_inherited_ace_conflict
|
||||||
|
].compact.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def forbidden_preconditions
|
||||||
|
[
|
||||||
|
limited_number_of_aces,
|
||||||
|
deny_before_grant,
|
||||||
|
grant_only,
|
||||||
|
no_invert,
|
||||||
|
no_abstract,
|
||||||
|
not_supported_priviledge,
|
||||||
|
missing_required_principal,
|
||||||
|
recognized_principal,
|
||||||
|
allowed_principal
|
||||||
|
].compact.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_error(response)
|
||||||
|
{ error: response }
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_ace_conflict
|
||||||
|
build_error 'no_ace_conflict'
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_protected_ace_conflict
|
||||||
|
build_error 'no-protected-ace-conflict'
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_inherited_ace_conflict
|
||||||
|
build_error 'no-inherited-ace-conflict'
|
||||||
|
end
|
||||||
|
|
||||||
|
def limited_number_of_aces
|
||||||
|
build_error 'limited-number-of-aces'
|
||||||
|
end
|
||||||
|
|
||||||
|
def deny_before_grant
|
||||||
|
build_error 'deny-before-grant'
|
||||||
|
end
|
||||||
|
|
||||||
|
def grant_only
|
||||||
|
build_error 'grant-only'
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_invert
|
||||||
|
build_error 'no-invert'
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_abstract
|
||||||
|
build_error 'no-abstract'
|
||||||
|
end
|
||||||
|
|
||||||
|
def not_supported_privilege
|
||||||
|
build_error 'not-supported-priviledge'
|
||||||
|
end
|
||||||
|
|
||||||
|
def missing_required_principal
|
||||||
|
build_error 'missing-required-principal'
|
||||||
|
end
|
||||||
|
|
||||||
|
def recognized_principal
|
||||||
|
build_error 'recognized-principal'
|
||||||
|
end
|
||||||
|
|
||||||
|
def allowed_principal
|
||||||
|
build_error 'allowed-principal'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -5,7 +5,7 @@ Calligraphy.configure do |config|
|
|||||||
# HTTP verbs and URLs and WebDAV controller actions.
|
# HTTP verbs and URLs and WebDAV controller actions.
|
||||||
# config.web_dav_actions = [
|
# config.web_dav_actions = [
|
||||||
# :options, :get, :put, :delete, :copy, :move,
|
# :options, :get, :put, :delete, :copy, :move,
|
||||||
# :mkcol, :propfind, :proppatch, :lock, :unlock
|
# :mkcol, :propfind, :proppatch, :lock, :unlock, :acl
|
||||||
# ]
|
# ]
|
||||||
|
|
||||||
# HTTP methods allowed by the WebDavRequests controller.
|
# HTTP methods allowed by the WebDavRequests controller.
|
||||||
@@ -15,7 +15,7 @@ Calligraphy.configure do |config|
|
|||||||
# HTTP 405 (Method Not Allowed) response.
|
# HTTP 405 (Method Not Allowed) response.
|
||||||
# config.allowed_http_methods = %w(
|
# config.allowed_http_methods = %w(
|
||||||
# options get put delete copy move
|
# options get put delete copy move
|
||||||
# mkcol propfind proppatch lock unlock
|
# mkcol propfind proppatch lock unlock acl
|
||||||
# )
|
# )
|
||||||
|
|
||||||
# If Digest Authentication is enabled by default. False by default.
|
# If Digest Authentication is enabled by default. False by default.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Calligraphy.configure do |config|
|
|||||||
# HTTP verbs and URLs and WebDAV controller actions.
|
# HTTP verbs and URLs and WebDAV controller actions.
|
||||||
# config.web_dav_actions = [
|
# config.web_dav_actions = [
|
||||||
# :options, :get, :put, :delete, :copy, :move,
|
# :options, :get, :put, :delete, :copy, :move,
|
||||||
# :mkcol, :propfind, :proppatch, :lock, :unlock
|
# :mkcol, :propfind, :proppatch, :lock, :unlock, :acl
|
||||||
# ]
|
# ]
|
||||||
|
|
||||||
# HTTP methods allowed by the WebDavRequests controller.
|
# HTTP methods allowed by the WebDavRequests controller.
|
||||||
@@ -13,7 +13,7 @@ Calligraphy.configure do |config|
|
|||||||
# HTTP 405 (Method Not Allowed) response.
|
# HTTP 405 (Method Not Allowed) response.
|
||||||
# config.allowed_http_methods = %w(
|
# config.allowed_http_methods = %w(
|
||||||
# options get put delete copy move
|
# options get put delete copy move
|
||||||
# mkcol propfind proppatch lock unlock
|
# mkcol propfind proppatch lock unlock acl
|
||||||
# )
|
# )
|
||||||
|
|
||||||
# If Digest Authentication is enabled by default. False by default.
|
# If Digest Authentication is enabled by default. False by default.
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
calligraphy_resource :test
|
calligraphy_resource :test
|
||||||
calligraphy_resource :webdav, resource_class: Calligraphy::FileResource, resource_root_path: File.expand_path('../../../../tmp/webdav', __FILE__)
|
calligraphy_resource :webdav,
|
||||||
|
resource_class: Calligraphy::FileResource,
|
||||||
|
resource_root_path: File.expand_path('../../../../tmp/webdav', __FILE__)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ require 'rspec/rails'
|
|||||||
# directory. Alternatively, in the individual `*_spec.rb` files, manually
|
# directory. Alternatively, in the individual `*_spec.rb` files, manually
|
||||||
# require only the support files necessary.
|
# require only the support files necessary.
|
||||||
#
|
#
|
||||||
Dir[Rails.root.join('../support/**/*.rb')].each { |f| require f }
|
# Dir[Rails.root.join('../support/**/*.rb')].each { |f| require f }
|
||||||
|
|
||||||
# Checks for pending migrations and applies them before tests are run.
|
# Checks for pending migrations and applies them before tests are run.
|
||||||
# If you are not using ActiveRecord, you can remove this line.
|
# If you are not using ActiveRecord, you can remove this line.
|
||||||
@@ -57,3 +57,5 @@ RSpec.configure do |config|
|
|||||||
# arbitrary gems may also be filtered via:
|
# arbitrary gems may also be filtered via:
|
||||||
# config.filter_gems_from_backtrace("gem name")
|
# config.filter_gems_from_backtrace("gem name")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require 'support/resource_helpers'
|
||||||
|
|||||||
33
spec/requests/acl_spec.rb
Normal file
33
spec/requests/acl_spec.rb
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
require 'support/request_helpers'
|
||||||
|
require 'support/examples/acl'
|
||||||
|
|
||||||
|
RSpec.describe 'acl', type: :request do
|
||||||
|
before(:context) do
|
||||||
|
Calligraphy::FileResource.setup
|
||||||
|
end
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
skip_authentication
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:context) do
|
||||||
|
Calligraphy::FileResource.cleanup
|
||||||
|
end
|
||||||
|
|
||||||
|
context "for #{Calligraphy::FileResource}" do
|
||||||
|
describe 'acl' do
|
||||||
|
before(:each) do
|
||||||
|
Calligraphy::FileResource.create resource: 'top'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'grants the proper privileges' do
|
||||||
|
acl '/webdav/top', headers: {
|
||||||
|
RAW_POST_DATA: Support::Examples::Acl.rfc3744_8_1_2
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -5,47 +5,47 @@ require 'support/request_helpers'
|
|||||||
require 'support/examples/ext_mkcol'
|
require 'support/examples/ext_mkcol'
|
||||||
|
|
||||||
RSpec.describe 'mkcol', type: :request do
|
RSpec.describe 'mkcol', type: :request do
|
||||||
before(:all) do
|
before(:context) do
|
||||||
tmp_dir = Rails.root.join('../../tmp').to_path
|
Calligraphy::FileResource.setup
|
||||||
Dir.mkdir tmp_dir unless File.exist? tmp_dir
|
|
||||||
|
|
||||||
webdav_dir = Rails.root.join('../../tmp/webdav').to_path
|
|
||||||
FileUtils.rm_r webdav_dir if File.exist? webdav_dir
|
|
||||||
Dir.mkdir webdav_dir
|
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
allow(Calligraphy).to receive(:enable_digest_authentication)
|
skip_authentication
|
||||||
.and_return(false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a collection with additional properties' do
|
after(:context) do
|
||||||
allow_any_instance_of(Calligraphy::FileResource).to receive(
|
Calligraphy::FileResource.cleanup
|
||||||
:valid_resourcetypes
|
|
||||||
).and_return(%w[collection special-resource])
|
|
||||||
|
|
||||||
expect(Dir).to receive(:mkdir).and_call_original
|
|
||||||
expect_any_instance_of(Calligraphy::FileResource).to receive(
|
|
||||||
:proppatch
|
|
||||||
)
|
|
||||||
|
|
||||||
mkcol '/webdav/special', headers: {
|
|
||||||
RAW_POST_DATA: Support::Examples::ExtMkcol.rfc5689_3_4
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(response.body.empty?).to eq(true)
|
|
||||||
expect(response.status).to eq(201)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with an invalid resource type' do
|
context "for #{Calligraphy::FileResource}" do
|
||||||
it 'returns an error response' do
|
it 'creates a collection with additional properties' do
|
||||||
|
allow_any_instance_of(Calligraphy::FileResource).to receive(
|
||||||
|
:valid_resourcetypes
|
||||||
|
).and_return(%w[collection special-resource])
|
||||||
|
|
||||||
|
expect(Dir).to receive(:mkdir).and_call_original
|
||||||
|
expect_any_instance_of(Calligraphy::FileResource).to receive(
|
||||||
|
:proppatch
|
||||||
|
)
|
||||||
|
|
||||||
mkcol '/webdav/special', headers: {
|
mkcol '/webdav/special', headers: {
|
||||||
RAW_POST_DATA: Support::Examples::ExtMkcol.rfc5689_3_4
|
RAW_POST_DATA: Support::Examples::ExtMkcol.rfc5689_3_4
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(response.status).to eq(403)
|
expect(response.body.empty?).to eq(true)
|
||||||
expect(response.body).to include('mkcol-response')
|
expect(response.status).to eq(201)
|
||||||
expect(response.body).to include('valid-resourcetype')
|
end
|
||||||
|
|
||||||
|
context 'with an invalid resource type' do
|
||||||
|
it 'returns an error response' do
|
||||||
|
mkcol '/webdav/special', headers: {
|
||||||
|
RAW_POST_DATA: Support::Examples::ExtMkcol.rfc5689_3_4
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
expect(response.body).to include('mkcol-response')
|
||||||
|
expect(response.body).to include('valid-resourcetype')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,48 +4,97 @@ require 'rails_helper'
|
|||||||
require 'support/request_helpers'
|
require 'support/request_helpers'
|
||||||
|
|
||||||
RSpec.describe 'OPTIONS', type: :request do
|
RSpec.describe 'OPTIONS', type: :request do
|
||||||
|
before(:context) do
|
||||||
|
Calligraphy::FileResource.setup
|
||||||
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
allow(Calligraphy).to receive(:enable_digest_authentication)
|
skip_authentication
|
||||||
.and_return(false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when not using extended MKCOL support' do
|
after(:context) do
|
||||||
before(:each) do
|
Calligraphy::FileResource.cleanup
|
||||||
allow_any_instance_of(Calligraphy::FileResource).to receive(
|
|
||||||
:enable_extended_mkcol?
|
|
||||||
).and_return(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'advertises support for all 3 WebDAV classes' do
|
|
||||||
options '/webdav/special'
|
|
||||||
|
|
||||||
%w[1 2 3].each { |c| expect(response.headers['DAV']).to include(c) }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not advertise support for extended-mkcol' do
|
|
||||||
options '/webdav/special'
|
|
||||||
|
|
||||||
expect(response.headers['DAV']).to_not include('extended-mkcol')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when using extended MKCOL support' do
|
context "for #{Calligraphy::FileResource}" do
|
||||||
before(:each) do
|
context 'when not using extended MKCOL support' do
|
||||||
allow_any_instance_of(Calligraphy::FileResource).to receive(
|
before(:each) do
|
||||||
:enable_extended_mkcol?
|
allow_any_instance_of(Calligraphy::FileResource).to receive(
|
||||||
).and_return(true)
|
:enable_extended_mkcol?
|
||||||
|
).and_return(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'advertises support for all 3 WebDAV classes' do
|
||||||
|
options '/webdav/special'
|
||||||
|
|
||||||
|
%w[1 2 3].each { |c| expect(response.headers['DAV']).to include(c) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not advertise support for extended-mkcol' do
|
||||||
|
options '/webdav/special'
|
||||||
|
|
||||||
|
expect(response.headers['DAV']).to_not include('extended-mkcol')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'advertises support for all 3 WebDAV classes' do
|
context 'when using extended MKCOL support' do
|
||||||
options '/webdav/special'
|
before(:each) do
|
||||||
|
allow_any_instance_of(Calligraphy::FileResource).to receive(
|
||||||
|
:enable_extended_mkcol?
|
||||||
|
).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
%w[1 2 3].each { |c| expect(response.headers['DAV']).to include(c) }
|
it 'advertises support for all 3 WebDAV classes' do
|
||||||
|
options '/webdav/special'
|
||||||
|
|
||||||
|
%w[1 2 3].each { |c| expect(response.headers['DAV']).to include(c) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'advertises support for extended-mkcol' do
|
||||||
|
options '/webdav/special'
|
||||||
|
|
||||||
|
expect(response.headers['DAV']).to include('extended-mkcol')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'advertises support for extended-mkcol' do
|
context 'when not using access control support' do
|
||||||
options '/webdav/special'
|
before(:each) do
|
||||||
|
allow_any_instance_of(Calligraphy::FileResource).to receive(
|
||||||
|
:enable_access_control?
|
||||||
|
).and_return(false)
|
||||||
|
end
|
||||||
|
|
||||||
expect(response.headers['DAV']).to include('extended-mkcol')
|
it 'advertises support for all 3 WebDAV classes' do
|
||||||
|
options '/webdav/special'
|
||||||
|
|
||||||
|
%w[1 2 3].each { |c| expect(response.headers['DAV']).to include(c) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not advertise support for access control' do
|
||||||
|
options '/webdav/special'
|
||||||
|
|
||||||
|
expect(response.headers['DAV']).to_not include('access-control')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using access control support' do
|
||||||
|
before(:each) do
|
||||||
|
allow_any_instance_of(Calligraphy::FileResource).to receive(
|
||||||
|
:enable_access_control?
|
||||||
|
).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'advertises support for all 3 WebDAV classes' do
|
||||||
|
options '/webdav/special'
|
||||||
|
|
||||||
|
%w[1 2 3].each { |c| expect(response.headers['DAV']).to include(c) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'advertises support for access control' do
|
||||||
|
options '/webdav/special'
|
||||||
|
|
||||||
|
expect(response.headers['DAV']).to include('access-control')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,25 +6,22 @@ require 'support/examples/propfind'
|
|||||||
require 'support/examples/proppatch'
|
require 'support/examples/proppatch'
|
||||||
|
|
||||||
RSpec.describe 'PROPFIND', type: :request do
|
RSpec.describe 'PROPFIND', type: :request do
|
||||||
before(:all) do
|
before(:context) do
|
||||||
tmp_dir = Rails.root.join('../../tmp').to_path
|
Calligraphy::FileResource.setup
|
||||||
Dir.mkdir tmp_dir unless File.exist? tmp_dir
|
|
||||||
|
|
||||||
webdav_dir = Rails.root.join('../../tmp/webdav').to_path
|
|
||||||
FileUtils.rm_r webdav_dir if File.exist? webdav_dir
|
|
||||||
Dir.mkdir webdav_dir
|
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
allow(Calligraphy).to receive(:enable_digest_authentication)
|
skip_authentication
|
||||||
.and_return(false)
|
end
|
||||||
|
|
||||||
|
after(:context) do
|
||||||
|
Calligraphy::FileResource.cleanup
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with xml defintiion' do
|
context 'with xml defintiion' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
put '/webdav/bar.html', headers: {
|
Calligraphy::FileResource.create resource: 'bar.html'
|
||||||
RAW_POST_DATA: 'hello world'
|
|
||||||
}
|
|
||||||
proppatch '/webdav/bar.html', headers: {
|
proppatch '/webdav/bar.html', headers: {
|
||||||
RAW_POST_DATA: Support::Examples::Proppatch.rfc4918_9_2_2
|
RAW_POST_DATA: Support::Examples::Proppatch.rfc4918_9_2_2
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,5 +46,26 @@ RSpec.describe 'Resource' do
|
|||||||
expect(resource.dav_compliance).to eq('1, 2, 3')
|
expect(resource.dav_compliance).to eq('1, 2, 3')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#enable_access_control?' do
|
||||||
|
it 'is not enabled by default' do
|
||||||
|
resource = Calligraphy::Resource.new
|
||||||
|
expect(resource.enable_access_control?).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#enable_extended_mkcol?' do
|
||||||
|
it 'is not enabled by default' do
|
||||||
|
resource = Calligraphy::Resource.new
|
||||||
|
expect(resource.enable_extended_mkcol?).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#valid_resourcetypes' do
|
||||||
|
it 'returns only a collection resourcetype by default' do
|
||||||
|
resource = Calligraphy::Resource.new
|
||||||
|
expect(resource.valid_resourcetypes).to match_array(['collection'])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -113,5 +113,25 @@ RSpec.describe 'calligraphy_resource', type: :routing do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'for HEAD requests' do
|
||||||
|
it do
|
||||||
|
expect(head: '/test/twelve').to route_to(
|
||||||
|
controller: 'calligraphy/rails/web_dav_requests',
|
||||||
|
action: 'invoke_method',
|
||||||
|
resource: 'twelve'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for ACL requests' do
|
||||||
|
it do
|
||||||
|
expect(acl: '/test/thirteen').to route_to(
|
||||||
|
controller: 'calligraphy/rails/web_dav_requests',
|
||||||
|
action: 'invoke_method',
|
||||||
|
resource: 'thirteen'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
40
spec/support/examples/acl.rb
Normal file
40
spec/support/examples/acl.rb
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# frozen_string_literal: false
|
||||||
|
|
||||||
|
module Support
|
||||||
|
module Examples
|
||||||
|
module Acl
|
||||||
|
# RFC3744: 8.1.2 The ACL method
|
||||||
|
def self.rfc3744_8_1_2
|
||||||
|
<<~XML
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<D:acl xmlns:D="DAV:">
|
||||||
|
<D:ace>
|
||||||
|
<D:principal>
|
||||||
|
<D:href>http://www.example.com/users/esedlar</D:href>
|
||||||
|
</D:principal>
|
||||||
|
<D:grant>
|
||||||
|
<D:privilege><D:read/></D:privilege>
|
||||||
|
<D:privilege><D:write/></D:privilege>
|
||||||
|
</D:grant>
|
||||||
|
</D:ace>
|
||||||
|
<D:ace>
|
||||||
|
<D:principal>
|
||||||
|
<D:property><D:owner/></D:property>
|
||||||
|
</D:principal>
|
||||||
|
<D:grant>
|
||||||
|
<D:privilege><D:read-acl/></D:privilege>
|
||||||
|
<D:privilege><D:write-acl/></D:privilege>
|
||||||
|
</D:grant>
|
||||||
|
</D:ace>
|
||||||
|
<D:ace>
|
||||||
|
<D:principal><D:all/></D:principal>
|
||||||
|
<D:grant>
|
||||||
|
<D:privilege><D:read/></D:privilege>
|
||||||
|
</D:grant>
|
||||||
|
</D:ace>
|
||||||
|
</D:acl>
|
||||||
|
XML
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,7 +4,7 @@ module ActionDispatch
|
|||||||
module Integration
|
module Integration
|
||||||
module RequestHelpers
|
module RequestHelpers
|
||||||
request_methods = %w[
|
request_methods = %w[
|
||||||
copy move mkcol options propfind proppatch lock unlock
|
copy move mkcol options propfind proppatch lock unlock acl
|
||||||
]
|
]
|
||||||
|
|
||||||
request_methods.each do |method|
|
request_methods.each do |method|
|
||||||
@@ -15,3 +15,7 @@ module ActionDispatch
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def skip_authentication
|
||||||
|
allow(Calligraphy).to receive(:enable_digest_authentication).and_return(false)
|
||||||
|
end
|
||||||
|
|||||||
49
spec/support/resource_helpers.rb
Normal file
49
spec/support/resource_helpers.rb
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RESOURCES_TO_TEST_AGAINST = [
|
||||||
|
Calligraphy::FileResource
|
||||||
|
].freeze
|
||||||
|
|
||||||
|
module RSpecMethods
|
||||||
|
def setup; end
|
||||||
|
|
||||||
|
def cleanup; end
|
||||||
|
|
||||||
|
def create(resource:, content: 'Hi hi!'); end
|
||||||
|
end
|
||||||
|
|
||||||
|
module FileResourceHelpers
|
||||||
|
def setup
|
||||||
|
tmp_dir = Rails.root.join('../../tmp').to_path
|
||||||
|
Dir.mkdir tmp_dir unless File.exist? tmp_dir
|
||||||
|
|
||||||
|
FileUtils.rm_r resource_root if File.exist? resource_root
|
||||||
|
Dir.mkdir resource_root
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup
|
||||||
|
FileUtils.rm_r resource_root if File.exist? resource_root
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(resource:, content: 'Hello world')
|
||||||
|
resource = Calligraphy::FileResource.new(
|
||||||
|
resource: resource,
|
||||||
|
root_dir: resource_root
|
||||||
|
)
|
||||||
|
resource.write content
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_root
|
||||||
|
Rails.root.join('../../tmp/webdav').to_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RESOURCES_TO_TEST_AGAINST.each do |resource_class|
|
||||||
|
resource_class.send :extend, RSpecMethods
|
||||||
|
end
|
||||||
|
|
||||||
|
module Calligraphy
|
||||||
|
class FileResource
|
||||||
|
extend FileResourceHelpers
|
||||||
|
end
|
||||||
|
end
|
||||||
37
web_dav_inputs_outputs.txt
Normal file
37
web_dav_inputs_outputs.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
Description
|
||||||
|
activelock
|
||||||
|
collection
|
||||||
|
depth
|
||||||
|
error
|
||||||
|
exclusive
|
||||||
|
href
|
||||||
|
location
|
||||||
|
lockentry
|
||||||
|
lockinfo
|
||||||
|
lockroot
|
||||||
|
lockscope
|
||||||
|
locktoken
|
||||||
|
locktype
|
||||||
|
multistatus
|
||||||
|
owner
|
||||||
|
prop
|
||||||
|
propstat
|
||||||
|
response
|
||||||
|
responsedescription
|
||||||
|
shared
|
||||||
|
status
|
||||||
|
timeout
|
||||||
|
write
|
||||||
|
|
||||||
|
|
||||||
|
Input
|
||||||
|
allprop
|
||||||
|
# include
|
||||||
|
prop
|
||||||
|
propertyupdate
|
||||||
|
propfind
|
||||||
|
propname
|
||||||
|
remove
|
||||||
|
set
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user