Skip to content

Commit

Permalink
Merge pull request #4839 from avalonmediasystem/cdl_stream_token
Browse files Browse the repository at this point in the history
Add CDL check to Stream token assignment
  • Loading branch information
cjcolvar authored Aug 26, 2022
2 parents 255cb92 + 582dfbb commit b8cb3b0
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 55 deletions.
12 changes: 6 additions & 6 deletions app/controllers/master_files_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Copyright 2011-2022, The Trustees of Indiana University and Northwestern
# University. Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
#
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
Expand Down Expand Up @@ -70,7 +70,7 @@ def show

def embed
if can? :read, @master_file
@stream_info = secure_streams(@master_file.stream_details)
@stream_info = secure_streams(@master_file.stream_details, @master_file.media_object_id)
@stream_info['t'] = view_context.parse_media_fragment(params[:t]) # add MediaFragment from params
@stream_info['link_back_url'] = view_context.share_link_for(@master_file)
end
Expand Down Expand Up @@ -411,14 +411,14 @@ def ensure_readable_filedata
end

def gather_hls_streams(master_file)
stream_info = secure_streams(master_file.stream_details)
stream_info = secure_streams(master_file.stream_details, master_file.media_object_id)
hls_streams = stream_info[:stream_hls].reject { |stream| stream[:quality] == 'auto' }
hls_streams.each { |stream| unnest_wowza_stream(stream) } if Settings.streaming.server == "wowza"
hls_streams
end

def hls_stream(master_file, quality)
stream_info = secure_streams(master_file.stream_details)
stream_info = secure_streams(master_file.stream_details, master_file.media_object_id)
hls_stream = stream_info[:stream_hls].select { |stream| stream[:quality] == quality }
unnest_wowza_stream(hls_stream&.first) if Settings.streaming.server == "wowza"
hls_stream
Expand Down
14 changes: 9 additions & 5 deletions app/controllers/media_objects_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Copyright 2011-2022, The Trustees of Indiana University and Northwestern
# University. Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
#
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
Expand Down Expand Up @@ -468,7 +468,7 @@ def manifest

master_files = master_file_presenters
canvas_presenters = master_files.collect do |mf|
stream_info = secure_streams(mf.stream_details)
stream_info = secure_streams(mf.stream_details, @media_object.id)
IiifCanvasPresenter.new(master_file: mf, stream_info: stream_info)
end
presenter = IiifManifestPresenter.new(media_object: @media_object, master_files: canvas_presenters)
Expand Down Expand Up @@ -546,7 +546,11 @@ def set_player_token
def load_current_stream
set_active_file
set_player_token
@currentStreamInfo = @currentStream.nil? ? {} : secure_streams(@currentStream.stream_details)
@currentStreamInfo = if params[:id]
@currentStream.nil? ? {} : secure_streams(@currentStream.stream_details, params[:id])
else
@currentStream.nil? ? {} : secure_streams(@currentStream.stream_details, @media_object.id)
end
@currentStreamInfo['t'] = view_context.parse_media_fragment(params[:t]) # add MediaFragment from params
@currentStreamInfo['lti_share_link'] = view_context.lti_share_url_for(@currentStream)
@currentStreamInfo['link_back_url'] = view_context.share_link_for(@currentStream)
Expand Down
20 changes: 15 additions & 5 deletions app/helpers/security_helper.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Copyright 2011-2022, The Trustees of Indiana University and Northwestern
# University. Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
#
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
Expand All @@ -19,13 +19,23 @@ def add_stream_cookies(stream_info)
end
end

def secure_streams(stream_info)
def secure_streams(stream_info, media_object_id)
add_stream_url(stream_info) unless not_checked_out?(media_object_id)
stream_info
end

def add_stream_url(stream_info)
add_stream_cookies(id: stream_info[:id])
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
quality[:url] = SecurityHandler.secure_url(quality[:url], session: session, target: stream_info[:id], protocol: protocol)
end
end
stream_info
end

private

def not_checked_out?(media_object_id)
Avalon::Configuration.controlled_digital_lending_enabled? && Checkout.checked_out_to_user(media_object_id, current_user&.id).empty?
end
end
1 change: 1 addition & 0 deletions app/models/checkout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Checkout < ApplicationRecord
scope :active_for_media_object, ->(media_object_id) { where(media_object_id: media_object_id).where("return_time > now()") }
scope :active_for_user, ->(user_id) { where(user_id: user_id).where("return_time > now()") }
scope :returned_for_user, ->(user_id) { where(user_id: user_id).where("return_time < now()") }
scope :checked_out_to_user, ->(media_object_id, user_id) { where("media_object_id = ? AND user_id = ? AND return_time > now()", media_object_id, user_id) }

def media_object
MediaObject.find(media_object_id)
Expand Down
6 changes: 3 additions & 3 deletions app/services/security_service.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Copyright 2011-2022, The Trustees of Indiana University and Northwestern
# University. Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
#
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
Expand Down
2 changes: 1 addition & 1 deletion app/views/playlists/_player.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Unless required by applicable law or agreed to in writing, software distributed
<% f_start = @current_clip.start_time / 1000.0 %>
<% f_end = @current_clip.end_time / 1000.0 %>
<% @currentStream = @current_masterfile %>
<% @currentStreamInfo = secure_streams(@currentStream.stream_details) %>
<% @currentStreamInfo = secure_streams(@currentStream.stream_details, @current_masterfile.media_object_id) %>
<% @currentStreamInfo['t'] = [f_start,f_end] %>

<% if can? :read, @current_masterfile %>
Expand Down
14 changes: 7 additions & 7 deletions spec/controllers/master_files_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Copyright 2011-2022, The Trustees of Indiana University and Northwestern
# University. Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
#
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
Expand Down Expand Up @@ -664,10 +664,10 @@ class << file

describe "#update" do
let(:master_file) { FactoryBot.create(:master_file, :with_media_object) }
subject { put('update', params: { id: master_file.id,
master_file: { title: "New label",
poster_offset: "00:00:03",
date_digitized: "2020-08-27",
subject { put('update', params: { id: master_file.id,
master_file: { title: "New label",
poster_offset: "00:00:03",
date_digitized: "2020-08-27",
permalink: "https://perma.link" }})}

before do
Expand Down
121 changes: 98 additions & 23 deletions spec/helpers/security_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Copyright 2011-2022, The Trustees of Indiana University and Northwestern
# University. Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
#
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
Expand All @@ -19,9 +19,12 @@
{:id=>"bk1289888", :label=>nil, :is_video=>true, :poster_image=>nil, :embed_code=>"", :stream_hls=>[{:quality=>nil, :mimetype=>nil, :format=>"other", :url=>"http://localhost:3000/6f69c008-06a4-4bad-bb60-26297f0b4c06/35bddaa0-fbb4-404f-ab76-58f22921529c/warning.mp4.m3u8"}], :captions_path=>nil, :captions_format=>nil, :duration=>200.0, :embed_title=>"Fugit veniam numquam harum et adipisci est est. - video.mp4"}
}
let(:secure_url) { "http://example.com/secure/id" }
let(:media_object) { FactoryBot.create(:media_object) }
let(:user) { FactoryBot.create(:user) }

before do
allow(SecurityHandler).to receive(:secure_url).and_return(secure_url)
allow(helper).to receive(:current_user).and_return(user)
end

context 'when AWS streaming server' do
Expand All @@ -38,25 +41,62 @@

describe '#add_stream_cookies' do
it 'adds security tokens to cookies' do
expect { helper.add_stream_cookies(stream_info) }.to change { controller.cookies.sum {|k,v| 1} }.by(1)
expect(controller.cookies[secure_cookies.first[0]]).to eq secure_cookies.first[1][:value]
expect { helper.add_stream_cookies(stream_info) }.to change { controller.cookies.sum {|k,v| 1} }.by(1)
expect(controller.cookies[secure_cookies.first[0]]).to eq secure_cookies.first[1][:value]
end
end

describe '#secure_streams' do
it 'sets secure cookies' do
expect { helper.secure_streams(stream_info) }.to change { controller.cookies.sum {|k,v| 1} }.by(1)
expect(controller.cookies[secure_cookies.first[0]]).to eq secure_cookies.first[1][:value]
context 'controlled digital lending is disabled' do
before { allow(Settings.controlled_digital_lending).to receive(:enable).and_return(false) }
it 'sets secure cookies' do
expect { helper.secure_streams(stream_info, media_object.id) }.to change { controller.cookies.sum {|k,v| 1} }.by(1)
expect(controller.cookies[secure_cookies.first[0]]).to eq secure_cookies.first[1][:value]
end

it 'rewrites urls in the stream_info' do
expect { helper.secure_streams(stream_info, media_object.id) }.to change { stream_info.slice(:stream_flash, :stream_hls).values.flatten.collect {|v| v[:url]} }
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
expect(quality[:url]).to eq secure_url
end
end
end
end
context 'controlled digital lending is enabled' do
before { allow(Settings.controlled_digital_lending).to receive(:enable).and_return(true) }
context 'the user has the item checked out' do
before { FactoryBot.create(:checkout, media_object_id: media_object.id, user_id: user.id)}
it 'sets secure cookies' do
expect { helper.secure_streams(stream_info, media_object.id) }.to change { controller.cookies.sum {|k,v| 1} }.by(1)
expect(controller.cookies[secure_cookies.first[0]]).to eq secure_cookies.first[1][:value]
end

it 'rewrites urls in the stream_info' do
expect { helper.secure_streams(stream_info) }.to change { stream_info.slice(:stream_flash, :stream_hls).values.flatten.collect {|v| v[:url]} }
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
expect(quality[:url]).to eq secure_url
end
end
end
it 'rewrites urls in the stream_info' do
expect { helper.secure_streams(stream_info, media_object.id) }.to change { stream_info.slice(:stream_flash, :stream_hls).values.flatten.collect {|v| v[:url]} }
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
expect(quality[:url]).to eq secure_url
end
end
end
end
context 'the user does not have the item checked out' do
it 'does not set secure cookies' do
expect { helper.secure_streams(stream_info, media_object.id) }.not_to change { controller.cookies.sum {|k,v| 1} }
expect(controller.cookies[secure_cookies.first[0]]).not_to eq secure_cookies.first[1][:value]
end

it 'does not rewrite urls in the stream_info' do
expect { helper.secure_streams(stream_info, media_object.id) }.not_to change { stream_info.slice(:stream_flash, :stream_hls).values.flatten.collect {|v| v[:url]} }
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
expect(quality[:url]).not_to eq secure_url
end
end
end
end
end
end
end

Expand All @@ -68,15 +108,50 @@
end

describe '#secure_streams' do
it 'sets secure cookies' do
expect { helper.secure_streams(stream_info) }.not_to change { controller.cookies.sum {|k,v| 1} }
context 'controlled digital lending is disabled' do
before { allow(Settings.controlled_digital_lending).to receive(:enable).and_return(false) }
it 'sets secure cookies' do
expect { helper.secure_streams(stream_info, media_object.id) }.not_to change { controller.cookies.sum {|k,v| 1} }
end

it 'rewrites urls in the stream_info' do
expect { helper.secure_streams(stream_info, media_object.id) }.to change { stream_info.slice(:stream_flash, :stream_hls).values.flatten.collect {|v| v[:url]} }
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
expect(quality[:url]).to eq secure_url
end
end
end
end
context 'controlled digital lending is enabled' do
before { allow(Settings.controlled_digital_lending).to receive(:enable).and_return(true) }
context 'the user has the item checked out' do
before { FactoryBot.create(:checkout, media_object_id: media_object.id, user_id: user.id)}
it 'sets secure cookies' do
expect { helper.secure_streams(stream_info, media_object.id) }.not_to change { controller.cookies.sum {|k,v| 1} }
end

it 'rewrites urls in the stream_info' do
expect { helper.secure_streams(stream_info, media_object.id) }.to change { stream_info.slice(:stream_flash, :stream_hls).values.flatten.collect {|v| v[:url]} }
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
expect(quality[:url]).to eq secure_url
end
end
end
end
context 'the user does not have the item checked out' do
it 'sets secure cookies' do
expect { helper.secure_streams(stream_info, media_object.id) }.not_to change { controller.cookies.sum {|k,v| 1} }
end

it 'rewrites urls in the stream_info' do
expect { helper.secure_streams(stream_info) }.to change { stream_info.slice(:stream_flash, :stream_hls).values.flatten.collect {|v| v[:url]} }
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
expect(quality[:url]).to eq secure_url
it 'does not rewrite urls in the stream_info' do
expect { helper.secure_streams(stream_info, media_object.id) }.not_to change { stream_info.slice(:stream_flash, :stream_hls).values.flatten.collect {|v| v[:url]} }
[:stream_hls].each do |protocol|
stream_info[protocol].each do |quality|
expect(quality[:url]).not_to eq secure_url
end
end
end
end
end
Expand Down
24 changes: 24 additions & 0 deletions spec/models/checkout_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
let(:user) { FactoryBot.create(:user) }
let(:media_object) { FactoryBot.create(:media_object) }
let!(:checkout) { FactoryBot.create(:checkout, user: user, media_object_id: media_object.id) }
let!(:user_checkout) { FactoryBot.create(:checkout, user: user) }
let!(:other_checkout) { FactoryBot.create(:checkout) }
let!(:expired_checkout) { FactoryBot.create(:checkout, user: user, media_object_id: media_object.id) }

before do
Expand All @@ -57,6 +59,10 @@
it 'does not return inactive checkouts' do
expect(Checkout.active_for_media_object(media_object.id)).not_to include(expired_checkout)
end

it 'does not return other checkouts' do
expect(Checkout.active_for_media_object(media_object.id)).not_to include(other_checkout)
end
end

describe 'active_for_user' do
Expand All @@ -67,6 +73,10 @@
it 'does not return inactive checkouts' do
expect(Checkout.active_for_user(user.id)).not_to include(expired_checkout)
end

it 'does not return other checkouts' do
expect(Checkout.active_for_media_object(media_object.id)).not_to include(other_checkout)
end
end

describe 'returned_for_user' do
Expand All @@ -77,6 +87,20 @@
it 'does return inactive checkouts' do
expect(Checkout.returned_for_user(user.id)).to include(expired_checkout)
end

it 'does not return other checkouts' do
expect(Checkout.active_for_media_object(media_object.id)).not_to include(other_checkout)
end
end

describe 'checked_out_to_user' do
it 'returns the specified checkout' do
expect(Checkout.checked_out_to_user(media_object.id, user.id)).to include(checkout)
end

it "does not return the user's other checkouts" do
expect(Checkout.checked_out_to_user(media_object.id, user.id)).not_to include(user_checkout)
end
end
end

Expand Down
Loading

0 comments on commit b8cb3b0

Please sign in to comment.