Merge branch 'master' into refactor_proforma_import_export

This commit is contained in:
Karol
2022-09-13 22:47:50 +02:00
67 changed files with 1199 additions and 601 deletions

View File

@ -70,6 +70,7 @@ jobs:
cp config/secrets.yml.ci config/secrets.yml
cp config/docker.yml.erb.ci config/docker.yml.erb
cp config/mnemosyne.yml.ci config/mnemosyne.yml
cp config/content_security_policy.yml.ci config/content_security_policy.yml
- name: Create database
env:

1
.gitignore vendored
View File

@ -4,6 +4,7 @@
/config/mnemosyne.yml
/config/secrets.yml
/config/docker.yml.erb
/config/content_security_policy.yml
/coverage
/log/*.*
/public/assets

View File

@ -33,7 +33,7 @@ gem 'prometheus_exporter'
gem 'pry-byebug'
gem 'puma'
gem 'pundit'
gem 'rails', '~> 6.1.6'
gem 'rails', '~> 6.1.7'
gem 'rails_admin', '< 3.0.0' # Blocked by https://github.com/railsadminteam/rails_admin/issues/3490
gem 'rails-i18n'
gem 'rails-timeago'
@ -42,7 +42,7 @@ gem 'rest-client'
gem 'rubytree'
gem 'rubyzip'
gem 'sass-rails'
gem 'shakapacker', '6.5.1'
gem 'shakapacker', '6.5.2'
gem 'slim-rails'
gem 'sorcery' # Causes a deprecation warning in Rails 6.0+, see: https://github.com/Sorcery/sorcery/pull/255
gem 'telegraf'
@ -55,6 +55,10 @@ gem 'mnemosyne-ruby'
gem 'sentry-rails'
gem 'sentry-ruby'
group :development do
gem 'web-console'
end
group :development, :staging do
gem 'better_errors'
gem 'binding_of_caller'
@ -67,7 +71,6 @@ group :development, :staging do
gem 'rubocop-performance'
gem 'rubocop-rails', require: false
gem 'rubocop-rspec'
gem 'web-console'
end
group :development, :test, :staging do

View File

@ -13,71 +13,71 @@ GEM
remote: https://rubygems.org/
specs:
ZenTest (4.12.1)
actioncable (6.1.6.1)
actionpack (= 6.1.6.1)
activesupport (= 6.1.6.1)
actioncable (6.1.7)
actionpack (= 6.1.7)
activesupport (= 6.1.7)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.1.6.1)
actionpack (= 6.1.6.1)
activejob (= 6.1.6.1)
activerecord (= 6.1.6.1)
activestorage (= 6.1.6.1)
activesupport (= 6.1.6.1)
actionmailbox (6.1.7)
actionpack (= 6.1.7)
activejob (= 6.1.7)
activerecord (= 6.1.7)
activestorage (= 6.1.7)
activesupport (= 6.1.7)
mail (>= 2.7.1)
actionmailer (6.1.6.1)
actionpack (= 6.1.6.1)
actionview (= 6.1.6.1)
activejob (= 6.1.6.1)
activesupport (= 6.1.6.1)
actionmailer (6.1.7)
actionpack (= 6.1.7)
actionview (= 6.1.7)
activejob (= 6.1.7)
activesupport (= 6.1.7)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.1.6.1)
actionview (= 6.1.6.1)
activesupport (= 6.1.6.1)
actionpack (6.1.7)
actionview (= 6.1.7)
activesupport (= 6.1.7)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.1.6.1)
actionpack (= 6.1.6.1)
activerecord (= 6.1.6.1)
activestorage (= 6.1.6.1)
activesupport (= 6.1.6.1)
actiontext (6.1.7)
actionpack (= 6.1.7)
activerecord (= 6.1.7)
activestorage (= 6.1.7)
activesupport (= 6.1.7)
nokogiri (>= 1.8.5)
actionview (6.1.6.1)
activesupport (= 6.1.6.1)
actionview (6.1.7)
activesupport (= 6.1.7)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (6.1.6.1)
activesupport (= 6.1.6.1)
activejob (6.1.7)
activesupport (= 6.1.7)
globalid (>= 0.3.6)
activemodel (6.1.6.1)
activesupport (= 6.1.6.1)
activemodel (6.1.7)
activesupport (= 6.1.7)
activemodel-serializers-xml (1.0.2)
activemodel (> 5.x)
activesupport (> 5.x)
builder (~> 3.1)
activerecord (6.1.6.1)
activemodel (= 6.1.6.1)
activesupport (= 6.1.6.1)
activestorage (6.1.6.1)
actionpack (= 6.1.6.1)
activejob (= 6.1.6.1)
activerecord (= 6.1.6.1)
activesupport (= 6.1.6.1)
activerecord (6.1.7)
activemodel (= 6.1.7)
activesupport (= 6.1.7)
activestorage (6.1.7)
actionpack (= 6.1.7)
activejob (= 6.1.7)
activerecord (= 6.1.7)
activesupport (= 6.1.7)
marcel (~> 1.0)
mini_mime (>= 1.1.0)
activesupport (6.1.6.1)
activesupport (6.1.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
amq-protocol (2.3.2)
ast (2.4.2)
autotest (5.0.0)
@ -164,7 +164,7 @@ GEM
websocket-driver (>= 0.5.1)
ffi (1.15.5)
forgery (0.8.1)
glob (0.3.0)
glob (0.3.1)
globalid (1.0.0)
activesupport (>= 5.0)
haml (5.2.2)
@ -179,7 +179,7 @@ GEM
domain_name (~> 0.5)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
i18n-js (4.0.0)
i18n-js (4.0.1)
glob
i18n
image_processing (1.12.2)
@ -206,7 +206,7 @@ GEM
hana (~> 1.3)
regexp_parser (~> 2.0)
uri_template (~> 0.7)
jwt (2.4.1)
jwt (2.5.0)
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2)
@ -254,7 +254,7 @@ GEM
mnemosyne-ruby (1.13.0)
activesupport (>= 4)
bunny
msgpack (1.5.4)
msgpack (1.5.6)
multi_json (1.15.0)
multi_xml (0.6.0)
nested_form (0.3.2)
@ -281,7 +281,7 @@ GEM
racc (~> 1.4)
nyan-cat-formatter (0.12.0)
rspec (>= 2.99, >= 2.14.2, < 4)
oauth (0.5.10)
oauth (0.5.14)
oauth2 (1.4.10)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
@ -305,8 +305,8 @@ GEM
pry (>= 0.13, < 0.15)
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (4.0.7)
puma (5.6.4)
public_suffix (5.0.0)
puma (5.6.5)
nio4r (~> 2.0)
pundit (2.2.0)
activesupport (>= 3.0.0)
@ -321,20 +321,20 @@ GEM
rack
rack-test (2.0.2)
rack (>= 1.3)
rails (6.1.6.1)
actioncable (= 6.1.6.1)
actionmailbox (= 6.1.6.1)
actionmailer (= 6.1.6.1)
actionpack (= 6.1.6.1)
actiontext (= 6.1.6.1)
actionview (= 6.1.6.1)
activejob (= 6.1.6.1)
activemodel (= 6.1.6.1)
activerecord (= 6.1.6.1)
activestorage (= 6.1.6.1)
activesupport (= 6.1.6.1)
rails (6.1.7)
actioncable (= 6.1.7)
actionmailbox (= 6.1.7)
actionmailer (= 6.1.7)
actionpack (= 6.1.7)
actiontext (= 6.1.7)
actionview (= 6.1.7)
activejob (= 6.1.7)
activemodel (= 6.1.7)
activerecord (= 6.1.7)
activestorage (= 6.1.7)
activesupport (= 6.1.7)
bundler (>= 1.15.0)
railties (= 6.1.6.1)
railties (= 6.1.7)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
@ -363,9 +363,9 @@ GEM
rails (>= 5.0, < 7)
remotipart (~> 1.3)
sassc-rails (>= 1.3, < 3)
railties (6.1.6.1)
actionpack (= 6.1.6.1)
activesupport (= 6.1.6.1)
railties (6.1.7)
actionpack (= 6.1.7)
activesupport (= 6.1.7)
method_source
rake (>= 12.2)
thor (~> 1.0)
@ -375,7 +375,7 @@ GEM
activerecord (>= 6.1.5)
activesupport (>= 6.1.5)
i18n
rb-fsevent (0.11.1)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rbtree (0.4.5)
@ -414,7 +414,7 @@ GEM
rspec-mocks (~> 3.10)
rspec-support (~> 3.10)
rspec-support (3.11.0)
rubocop (1.35.0)
rubocop (1.36.0)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.1.2.1)
@ -463,8 +463,8 @@ GEM
sentry-ruby (~> 5.4.2)
sentry-ruby (5.4.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
set (1.0.2)
shakapacker (6.5.1)
set (1.0.3)
shakapacker (6.5.2)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
@ -499,9 +499,9 @@ GEM
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
ssrf_filter (1.0.8)
ssrf_filter (1.1.1)
strscan (3.0.4)
telegraf (2.1.0)
telegraf (2.1.1)
influxdb
temple (0.8.2)
thor (1.2.1)
@ -590,7 +590,7 @@ DEPENDENCIES
puma
pundit
rack-mini-profiler
rails (~> 6.1.6)
rails (~> 6.1.7)
rails-controller-testing
rails-i18n
rails-timeago
@ -611,7 +611,7 @@ DEPENDENCIES
selenium-webdriver
sentry-rails
sentry-ruby
shakapacker (= 6.5.1)
shakapacker (= 6.5.2)
shoulda-matchers
simplecov
slim-rails

View File

@ -32,4 +32,7 @@ $.jstree.defaults.core.worker = false;
// See https://github.com/rails/jquery-ujs/issues/456 for details
$(document).on('turbolinks:load', function(){
$.rails.refreshCSRFTokens();
$('.reloadCurrentPage').on('click', function() {
window.location.reload();
});
});

View File

@ -78,22 +78,12 @@ var CodeOceanEditor = {
if ($('#output-' + index).isPresent()) {
return $('#output-' + index);
} else {
var element = $('<pre class="mb-2">').attr('id', 'output-' + index);
var element = $('<div class="mb-2 output-element">').attr('id', 'output-' + index);
$('#output').append(element);
return element;
}
},
findOrCreateRenderElement: function (index) {
if ($('#render-' + index).isPresent()) {
return $('#render-' + index);
} else {
var element = $('<div>').attr('id', 'render-' + index);
$('#render').append(element);
return element;
}
},
getCardClass: function (result) {
if (result.file_role === 'teacher_defined_linter') {
return 'card bg-info text-white'
@ -648,7 +638,7 @@ var CodeOceanEditor = {
augmentStacktraceInOutput: function () {
if (this.tracepositions_regex) {
$('#output>pre').each($.proxy(function(index, element) {
$('#output > .output-element').each($.proxy(function(index, element) {
element = $(element)
const text = _.escape(element.text());
@ -656,16 +646,11 @@ var CodeOceanEditor = {
let matches;
// Switch both lines below to enable the output of images and render <IMG/> tags.
// Also consider `printOutput` in evaluation.js
// let augmented_text = element.text();
let augmented_text = element.html();
while (matches = this.tracepositions_regex.exec(text)) {
const frame = $('div.frame[data-filename="' + matches[1] + '"]')
if (frame.length > 0) {
// augmented_text = augmented_text.replace(new RegExp(matches[0], 'g'), "<a href='#' data-file='" + matches[1] + "' data-line='" + matches[2] + "'>" + matches[0] + "</a>");
augmented_text = augmented_text.replace(new RegExp(_.unescape(matches[0]), 'g'), "<a href='#' data-file='" + matches[1] + "' data-line='" + matches[2] + "'>" + matches[0] + "</a>");
}
}

View File

@ -174,11 +174,6 @@ CodeOceanEditorEvaluation = {
/**
* Output-Logic
*/
renderWebsocketOutput: function (msg) {
var element = this.findOrCreateRenderElement(0);
element.append(msg.data);
},
printWebsocketOutput: function (msg) {
if (!msg.data || msg.data === "\r") {
return;
@ -189,7 +184,7 @@ CodeOceanEditorEvaluation = {
},
clearOutput: function () {
$('#output pre').remove();
$('#output > .output-element').remove();
CodeOceanEditorTurtle.hideCanvas();
},
@ -207,43 +202,54 @@ CodeOceanEditorEvaluation = {
return;
}
if (output.stdout !== undefined && !output.stdout.startsWith("<img")) {
output.stdout = _.escape(output.stdout);
const sanitizedStdout = this.sanitizeOutput(output.stdout);
const sanitizedStderr = this.sanitizeOutput(output.stderr);
const element = this.findOrCreateOutputElement(index);
const pre = $('<span>');
if (sanitizedStdout !== '') {
if (colorize) {
pre.addClass('text-success');
}
pre.append(sanitizedStdout)
}
var element = this.findOrCreateOutputElement(index);
// Switch all four lines below to enable the output of images and render <IMG/> tags.
// Also consider `augmentStacktraceInOutput` in editor.js.erb
if (!colorize) {
if (output.stdout !== undefined && output.stdout !== '') {
output.stdout = output.stdout.replace(this.nonPrintableRegEx, "")
element.append(output.stdout)
//element.text(element.text() + output.stdout)
if (sanitizedStderr !== '') {
if (colorize) {
pre.addClass('text-warning');
} else {
pre.append('StdErr: ');
}
if (output.stderr !== undefined && output.stderr !== '') {
output.stderr = output.stderr.replace(this.nonPrintableRegEx, "")
element.append('StdErr: ' + output.stderr);
//element.text('StdErr: ' + element.text() + output.stderr);
}
} else if (output.stderr) {
output.stderr = output.stderr.replace(this.nonPrintableRegEx, "")
element.addClass('text-warning').append(output.stderr);
//element.addClass('text-warning').text(element.text() + output.stderr);
this.QaApiOutputBuffer.stderr += output.stderr;
} else if (output.stdout) {
output.stdout = output.stdout.replace(this.nonPrintableRegEx, "")
element.addClass('text-success').append(output.stdout);
//element.addClass('text-success').text(element.text() + output.stdout);
this.QaApiOutputBuffer.stdout += output.stdout;
} else {
element.addClass('text-muted').text($('#output').data('message-no-output'));
pre.append(sanitizedStderr);
}
if (sanitizedStdout === '' && sanitizedStderr === '') {
if (colorize) {
pre.addClass('text-muted');
}
pre.text($('#output').data('message-no-output'))
}
element.append(pre);
},
sanitizeOutput: function (rawContent) {
let sanitizedContent = _.escape(rawContent).replace(this.nonPrintableRegEx, "");
if (rawContent !== undefined && rawContent.trim().startsWith("<img")) {
const doc = new DOMParser().parseFromString(rawContent, "text/html");
// Get the parsed element, it is automatically wrapped in a <html><body> document
const parsedElement = doc.firstChild.lastChild.firstChild;
if (parsedElement.src.startsWith("data:image")) {
const sanitizedImg = document.createElement('img');
sanitizedImg.src = parsedElement.src;
sanitizedContent = sanitizedImg.outerHTML;
}
}
return sanitizedContent;
},
getDeadlineInformation: function(deadline, translation_key, otherwise) {

View File

@ -44,7 +44,7 @@ CodeOceanEditorWebsocket = {
this.websocket.on('clear', this.clearOutput.bind(this));
this.websocket.on('turtle', this.handleTurtleCommand.bind(this));
this.websocket.on('turtlebatch', this.handleTurtlebatchCommand.bind(this));
this.websocket.on('render', this.renderWebsocketOutput.bind(this));
this.websocket.on('render', this.printWebsocketOutput.bind(this));
this.websocket.on('exit', this.handleExitCommand.bind(this));
this.websocket.on('status', this.showStatus.bind(this));
this.websocket.on('hint', this.showHint.bind(this));

View File

@ -7,7 +7,7 @@
renderPagedown = function() {
$(".wmd-output").each(function (i) {
const converter = new Markdown.Converter();
const converter = Markdown.getSanitizingConverter();
const content = $(this).html();
return $(this).html(converter.makeHtml(content));
})
@ -20,7 +20,7 @@ createPagedownEditor = function( selector, context ) {
return;
}
const attr = $(input).attr('id').split('wmd-input')[1];
const converter = new Markdown.Converter();
const converter = Markdown.getSanitizingConverter();
Markdown.Extra.init(converter);
const help = {
handler() {

View File

@ -25,7 +25,7 @@ i.fa-solid, i.fa-regular, i.fa-solid {
margin-right: 0.5em;
}
pre {
pre, .output-element {
background-color: #FAFAFA;
margin: 0;
padding: .25rem!important;

View File

@ -20,6 +20,9 @@
}
}
#content-left-sidebar, #content-right-sidebar {
min-height: 250px;
}
.frame {
display: none;
@ -77,20 +80,13 @@
overflow: auto;
}
#outputInformation {
#output {
max-height: 500px;
width: 100%;
#output {
white-space: pre;
font-family: var(--bs-font-monospace);
font-size: 14px;
.output-element {
overflow: auto;
margin: 2em 0;
p {
margin: 0.5em;
}
pre + pre {
margin-top: 1em;
}
}
}

View File

@ -9,7 +9,7 @@ class ApplicationController < ActionController::Base
after_action :verify_authorized, except: %i[welcome]
around_action :mnemosyne_trace
around_action :switch_locale
before_action :set_sentry_context, :allow_iframe_requests, :load_embed_options
before_action :set_sentry_context, :load_embed_options
protect_from_forgery(with: :exception, prepend: true)
rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized
rescue_from ActionController::InvalidAuthenticityToken, with: :render_csrf_error
@ -40,7 +40,10 @@ class ApplicationController < ActionController::Base
token = AuthenticationToken.find_by(shared_secret: params[:token])
return unless token
auto_login(token.user) if token.expire_at.future?
if token.expire_at.future?
token.update(expire_at: Time.zone.now)
auto_login(token.user)
end
end
def set_sentry_context
@ -93,10 +96,6 @@ class ApplicationController < ActionController::Base
# Show root page
end
def allow_iframe_requests
response.headers.delete('X-Frame-Options')
end
def load_embed_options
@embed_options = if session[:embed_options].present? && session[:embed_options].is_a?(Hash)
session[:embed_options].symbolize_keys

View File

@ -10,6 +10,15 @@ module CodeOcean
end
private :authorize!
def show_protected_upload
@file = CodeOcean::File.find(params[:id])
authorize!
raise Pundit::NotAuthorizedError if @embed_options[:disable_download] || @file.name_with_extension != params[:filename]
real_location = Pathname(@file.native_file.current_path).realpath
send_file(real_location, type: @file.native_file.content_type, filename: @file.name_with_extension, disposition: 'attachment')
end
def create
@file = CodeOcean::File.new(file_params)
if @file.file_template_id

View File

@ -5,8 +5,14 @@ module FileParameters
if exercise && params
params.reject do |_, file_attributes|
file = CodeOcean::File.find_by(id: file_attributes[:file_id])
next true if file.nil? || file.hidden || file.read_only
# avoid that public files from other contexts can be created
file.nil? || file.hidden || file.read_only || (file.context_type == 'Exercise' && file.context_id != exercise.id) || (file.context_type == 'CommunitySolution' && controller_name != 'community_solutions')
# `next` is similar to an early return and will proceed with the next iteration of the loop
next true if file.context_type == 'Exercise' && file.context_id != exercise.id
next true if file.context_type == 'Submission' && file.context.user != current_user
next true if file.context_type == 'CommunitySolution' && controller_name != 'community_solutions'
false
end
else
[]

View File

@ -22,6 +22,8 @@ class ExercisesController < ApplicationController
skip_after_action :verify_authorized, only: %i[import_exercise import_uuid_check]
skip_after_action :verify_policy_scoped, only: %i[import_exercise import_uuid_check], raise: false
rescue_from Pundit::NotAuthorizedError, with: :not_authorized_for_exercise
def authorize!
authorize(@exercise || @exercises)
end
@ -294,8 +296,6 @@ class ExercisesController < ApplicationController
private :update_exercise_tips
def implement
redirect_to(@exercise, alert: t('exercises.implement.unpublished')) if @exercise.unpublished? && current_user.role != 'admin' && current_user.role != 'teacher' # TODO: TESTESTEST
redirect_to(@exercise, alert: t('exercises.implement.no_files')) unless @exercise.files.visible.exists?
user_solved_exercise = @exercise.solved_by?(current_user)
count_interventions_today = UserExerciseIntervention.where(user: current_user).where('created_at >= ?',
Time.zone.now.beginning_of_day).count
@ -324,6 +324,8 @@ class ExercisesController < ApplicationController
end
end
@embed_options[:disable_score] = true unless @exercise.teacher_defined_assessment?
@hide_rfc_button = @embed_options[:disable_rfc]
@search = Search.new
@ -432,6 +434,19 @@ class ExercisesController < ApplicationController
authorize!
end
def not_authorized_for_exercise(_exception)
return render_not_authorized unless current_user
return render_not_authorized unless %w[implement working_times intervention search reload].include?(action_name)
if current_user.admin? || current_user.teacher?
redirect_to(@exercise, alert: t('exercises.implement.unpublished')) if @exercise.unpublished?
redirect_to(@exercise, alert: t('exercises.implement.no_files')) unless @exercise.files.visible.exists?
else
render_not_authorized
end
end
private :not_authorized_for_exercise
def set_execution_environments
@execution_environments = ExecutionEnvironment.all.order(:name)
end

View File

@ -9,7 +9,7 @@ class ExternalUsersController < ApplicationController
private :authorize!
def index
@search = ExternalUser.ransack(params[:q])
@search = ExternalUser.ransack(params[:q], {auth_object: current_user})
@users = @search.result.in_study_group_of(current_user).includes(:consumer).paginate(page: params[:page], per_page: per_page_param)
authorize!
end
@ -43,15 +43,15 @@ class ExternalUsersController < ApplicationController
(created_at - lag(created_at) over (PARTITION BY user_id, exercise_id
ORDER BY created_at)) AS working_time
FROM submissions
WHERE user_id = #{@user.id}
WHERE #{ExternalUser.sanitize_sql(['user_id = ?', @user.id])}
AND user_type = 'ExternalUser'
#{current_user.admin? ? '' : "AND study_group_id IN (#{current_user.study_groups.pluck(:id).join(', ')}) AND cause = 'submit'"}
#{current_user.admin? ? '' : "AND #{ExternalUser.sanitize_sql(['study_group_id IN (?)', current_user.study_groups.pluck(:id)])} AND cause = 'submit'"}
GROUP BY exercise_id,
user_id,
id
) AS foo
) AS bar
#{tag.nil? ? '' : " JOIN exercise_tags et ON et.exercise_id = bar.exercise_id AND et.tag_id = #{tag} "}
#{tag.nil? ? '' : " JOIN exercise_tags et ON et.exercise_id = bar.exercise_id AND #{ExternalUser.sanitize_sql(['et.tag_id = ?', tag])}"}
GROUP BY user_id,
bar.exercise_id;
"
@ -60,10 +60,14 @@ class ExternalUsersController < ApplicationController
def statistics
@user = ExternalUser.find(params[:id])
authorize!
if params[:tag].present?
tag = Tag.find(params[:tag])
authorize(tag, :show?)
end
statistics = {}
ApplicationRecord.connection.execute(working_time_query(params[:tag])).each do |tuple|
ApplicationRecord.connection.execute(working_time_query(tag&.id)).each do |tuple|
statistics[tuple['exercise_id'].to_i] = tuple
end

View File

@ -67,7 +67,7 @@ class InternalUsersController < ApplicationController
end
def index
@search = InternalUser.ransack(params[:q])
@search = InternalUser.ransack(params[:q], {auth_object: current_user})
@users = @search.result.includes(:consumer).order(:name).paginate(page: params[:page], per_page: per_page_param)
authorize!
end

View File

@ -70,12 +70,9 @@ class ProxyExercisesController < ApplicationController
def show
@search = @proxy_exercise.exercises.ransack
@exercises = @proxy_exercise.exercises.ransack.result.order(:title) # @search.result.order(:title)
@exercises = @proxy_exercise.exercises.ransack.result.order(:title)
end
# we might want to think about auth here
def reload; end
def update
myparams = proxy_exercise_params
myparams[:exercises] = Exercise.find(myparams[:exercise_ids].compact_blank)

View File

@ -12,7 +12,17 @@ class SubmissionsController < ApplicationController
before_action :set_testrun, only: %i[run score test]
before_action :set_files, only: %i[download show]
before_action :set_files_and_specific_file, only: %i[download_file render_file run test]
before_action :set_mime_type, only: %i[download_file render_file]
before_action :set_content_type_nosniff, only: %i[download download_file render_file]
# Overwrite the CSP header for the :render_file action
content_security_policy only: :render_file do |policy|
policy.img_src :none
policy.script_src :none
policy.font_src :none
policy.style_src :none
policy.connect_src :none
policy.form_action :none
end
def create
@submission = Submission.new(submission_params)
@ -56,7 +66,11 @@ class SubmissionsController < ApplicationController
def download_file
raise Pundit::NotAuthorizedError if @embed_options[:disable_download]
send_data(@file.read, filename: @file.name_with_extension)
if @file.native_file?
redirect_to protected_upload_path(id: @file.id, filename: @file.name_with_extension)
else
send_data(@file.content, filename: @file.name_with_extension, disposition: 'attachment')
end
end
def index
@ -66,13 +80,13 @@ class SubmissionsController < ApplicationController
end
def render_file
if @file.native_file?
send_data(@file.read, filename: @file.name_with_extension, disposition: 'inline')
else
render(plain: @file.content)
end
# If a file should not be downloaded, it should not be rendered either
raise Pundit::NotAuthorizedError if @embed_options[:disable_download]
send_data(@file.read, filename: @file.name_with_extension, disposition: 'inline')
end
# rubocop:disable Metrics/CyclomaticComplexity
def run
# These method-local socket variables are required in order to use one socket
# in the callbacks of the other socket. As the callbacks for the client socket
@ -83,7 +97,7 @@ class SubmissionsController < ApplicationController
client_socket = tubesock
client_socket.onopen do |_event|
kill_client_socket(client_socket) if @embed_options[:disable_run]
return kill_client_socket(client_socket) if @embed_options[:disable_run]
end
client_socket.onclose do |_event|
@ -167,7 +181,8 @@ class SubmissionsController < ApplicationController
@testrun[:status] = :failed
"\n#{t('exercises.implement.exit_failure', timestamp: l(Time.zone.now, format: :short), exit_code: exit_code)}"
end
send_and_store client_socket, {cmd: :write, stream: :stdout, data: "#{exit_statement}\n"}
stream = @testrun[:status] == :ok ? :stdout : :stderr
send_and_store client_socket, {cmd: :write, stream: stream, data: "#{exit_statement}\n"}
if exit_code == 137
send_and_store client_socket, {cmd: :status, status: :out_of_memory}
@testrun[:status] = :out_of_memory
@ -194,12 +209,13 @@ class SubmissionsController < ApplicationController
ensure
save_testrun_output 'run'
end
# rubocop:enable Metrics/CyclomaticComplexity:
def score
hijack do |tubesock|
tubesock.onopen do |_event|
switch_locale do
kill_client_socket(tubesock) if @embed_options[:disable_score]
return kill_client_socket(tubesock) if @embed_options[:disable_score] || !@submission.exercise.teacher_defined_assessment?
# The score is stored separately, we can forward it to the client immediately
tubesock.send_data(JSON.dump(@submission.calculate_score))
@ -226,7 +242,7 @@ class SubmissionsController < ApplicationController
hijack do |tubesock|
tubesock.onopen do |_event|
switch_locale do
kill_client_socket(tubesock) if @embed_options[:disable_run]
return kill_client_socket(tubesock) if @embed_options[:disable_run]
# The score is stored separately, we can forward it to the client immediately
tubesock.send_data(JSON.dump(@submission.test(@file)))
@ -363,9 +379,9 @@ class SubmissionsController < ApplicationController
@files = @submission.collect_files.select(&:visible)
end
def set_mime_type
@mime_type = Mime::Type.lookup_by_extension(@file.file_type.file_extension.gsub(/^\./, ''))
response.headers['Content-Type'] = @mime_type.to_s
def set_content_type_nosniff
# When sending a file, we want to ensure that browsers follow our Content-Type header
response.headers['X-Content-Type-Options'] = 'nosniff'
end
def set_submission

View File

@ -74,7 +74,7 @@ class UserExerciseFeedbacksController < ApplicationController
def update
submission = begin
current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first
current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').final.first
rescue StandardError
nil
end
@ -127,14 +127,16 @@ class UserExerciseFeedbacksController < ApplicationController
user_type = current_user.class.name
latest_submission = Submission
.where(user_id: user_id, user_type: user_type, exercise_id: exercise_id)
.order(created_at: :desc).first
.order(created_at: :desc).final.first
authorize(latest_submission, :show?)
params[:user_exercise_feedback]
.permit(:feedback_text, :difficulty, :exercise_id, :user_estimated_worktime)
.merge(user_id: user_id,
user_type: user_type,
submission: latest_submission,
normalized_score: latest_submission.normalized_score)
normalized_score: latest_submission&.normalized_score)
end
def validate_inputs(uef_params)

View File

@ -8,7 +8,7 @@ module ExerciseHelper
end
def qa_js_tag
javascript_include_tag "#{qa_url}/assets/qa_api.js"
javascript_include_tag "#{qa_url}/assets/qa_api.js", integrity: true, crossorigin: 'anonymous'
end
def qa_url

View File

@ -23,7 +23,7 @@ class UserMailer < ApplicationMailer
token = AuthenticationToken.generate!(request_for_comment.user)
@receiver_displayname = request_for_comment.user.displayname
@commenting_user_displayname = commenting_user.displayname
@comment_text = comment.text
@comment_text = ERB::Util.html_escape comment.text
@rfc_link = request_for_comment_url(request_for_comment, token: token.shared_secret)
mail(
subject: t('mailers.user_mailer.got_new_comment.subject',
@ -35,7 +35,7 @@ class UserMailer < ApplicationMailer
token = AuthenticationToken.generate!(subscription.user)
@receiver_displayname = subscription.user.displayname
@author_displayname = from_user.displayname
@comment_text = comment.text
@comment_text = ERB::Util.html_escape comment.text
@rfc_link = request_for_comment_url(subscription.request_for_comment, token: token.shared_secret)
@unsubscribe_link = unsubscribe_subscription_url(subscription)
mail(
@ -45,10 +45,10 @@ class UserMailer < ApplicationMailer
end
def send_thank_you_note(request_for_comment, receiver)
token = AuthenticationToken.generate!(request_for_comment.user)
token = AuthenticationToken.generate!(receiver)
@receiver_displayname = receiver.displayname
@author = request_for_comment.user.displayname
@thank_you_note = request_for_comment.thank_you_note
@thank_you_note = ERB::Util.html_escape request_for_comment.thank_you_note
@rfc_link = request_for_comment_url(request_for_comment, token: token.shared_secret)
mail(subject: t('mailers.user_mailer.send_thank_you_note.subject', author: @author), to: receiver.email)
end

View File

@ -4,6 +4,7 @@ class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
before_validation :strip_strings
before_validation :remove_null_bytes
def strip_strings
# trim whitespace from beginning and end of string attributes
@ -16,6 +17,15 @@ class ApplicationRecord < ActiveRecord::Base
end
end
def remove_null_bytes
# remove null bytes from string attributes
attribute_names.each do |name|
if send(name.to_sym).respond_to?(:tr)
send("#{name}=".to_sym, send(name).tr("\0", ''))
end
end
end
def self.ransackable_associations(_auth_object = nil)
[]
end

View File

@ -58,8 +58,7 @@ module CodeOcean
def read
if native_file?
valid = Pathname(native_file.current_path).fnmatch? ::File.join(native_file.root, '**')
return nil unless valid
return nil unless native_file_location_valid?
native_file.read
else
@ -67,6 +66,12 @@ module CodeOcean
end
end
def native_file_location_valid?
real_location = Pathname(native_file.current_path).realpath
upload_location = Pathname(::File.join(native_file.root, 'uploads')).realpath
real_location.fnmatch? ::File.join(upload_location.to_s, '**')
end
def ancestor_id
file_id || id
end

View File

@ -205,6 +205,10 @@ class Exercise < ApplicationRecord
"
end
def teacher_defined_assessment?
files.any?(&:teacher_defined_assessment?)
end
def get_working_times_for_study_group(study_group_id, user = nil)
user_progress = []
additional_user_data = []
@ -251,7 +255,6 @@ class Exercise < ApplicationRecord
end
def get_quantiles(quantiles)
quantiles_str = self.class.sanitize_sql("[#{quantiles.join(',')}]")
result = ActiveRecord::Base.transaction do
self.class.connection.execute("
SET LOCAL intervalstyle = 'iso_8601';
@ -358,7 +361,7 @@ class Exercise < ApplicationRecord
GROUP BY e.external_id,
f.user_id,
exercise_id )
SELECT unnest(percentile_cont(array#{quantiles_str}) within GROUP (ORDER BY working_time))
SELECT unnest(percentile_cont(#{self.class.sanitize_sql(['array[?]', quantiles])}) within GROUP (ORDER BY working_time))
FROM result
")
end

View File

@ -42,7 +42,11 @@ class User < ApplicationRecord
displayname
end
def self.ransackable_attributes(_auth_object = nil)
%w[name email external_id consumer_id role]
def self.ransackable_attributes(auth_object)
if auth_object.admin?
%w[name email external_id consumer_id role]
else
%w[name external_id]
end
end
end

View File

@ -7,6 +7,8 @@ module CodeOcean
end
def show?
return false if @record.native_file? && !@record.native_file_location_valid?
if @record.context.is_a?(Exercise)
admin? || author? || !@record.hidden
else
@ -14,6 +16,16 @@ module CodeOcean
end
end
def show_protected_upload?
return false if @record.native_file? && !@record.native_file_location_valid?
if @record.context.is_a?(Exercise)
admin? || author? || (!@record.context.unpublished && !@record.hidden)
else
admin? || author?
end
end
def create?
if @record.context.is_a?(Exercise)
admin? || author?

View File

@ -29,8 +29,16 @@ class ExercisePolicy < AdminOrAuthorPolicy
define_method(action) { (admin? || teacher_in_study_group? || author?) && @user.codeharbor_link }
end
%i[implement? working_times? intervention? search? submit? reload?].each do |action|
define_method(action) { everyone }
%i[implement? working_times? intervention? search? reload?].each do |action|
define_method(action) do
return no_one unless @record.files.visible.exists?
admin? || teacher_in_study_group? || author? || (everyone && !@record.unpublished?)
end
end
def submit?
everyone && @record.teacher_defined_assessment?
end
class Scope < Scope
@ -39,8 +47,8 @@ class ExercisePolicy < AdminOrAuthorPolicy
@scope.all
elsif @user.teacher?
@scope.where(
'user_id IN (SELECT user_id FROM study_group_memberships WHERE study_group_id IN (?))
OR (user_id = ? AND user_type = ?)
'exercises.user_id IN (SELECT user_id FROM study_group_memberships WHERE study_group_id IN (?))
OR (exercises.user_id = ? AND exercises.user_type = ?)
OR public = TRUE',
@user.study_groups.pluck(:id),
@user.id, @user.class.name

View File

@ -13,10 +13,6 @@ class ProxyExercisePolicy < AdminOrAuthorPolicy
define_method(action) { admin? || author? }
end
[:reload?].each do |action|
define_method(action) { everyone }
end
class Scope < Scope
def resolve
if @user.admin?

View File

@ -79,7 +79,7 @@ div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-botto
.heading = t('exercises.implement.error_hints.heading')
ul.body.mb-0
#output
pre.overflow-scroll = t('exercises.implement.no_output_yet')
.output-element.overflow-scroll = t('exercises.implement.no_output_yet')
- if CodeOcean::Config.new(:code_ocean).read[:flowr][:enabled] && !@embed_options[:disable_hints] && !@embed_options[:hide_test_results]
#flowrHint.mb-2.card.text-white.bg-info data-url=CodeOcean::Config.new(:code_ocean).read[:flowr][:url] role='tab'
.card-header = t('exercises.implement.flowr.heading')

View File

@ -25,7 +25,7 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise))
span.date = feedback.created_at
.card-collapse role="tabpanel"
.card-body.feedback
.text = render_markdown(feedback.feedback_text)
.text style="white-space: pre-wrap;" = feedback.feedback_text
.difficulty = "#{t('user_exercise_feedback.difficulty')} #{comment_presets[feedback.difficulty].join(' - ')}" if feedback.difficulty
.worktime = "#{t('user_exercise_feedback.working_time')} #{time_presets[feedback.user_estimated_worktime].join(' - ')}" if feedback.user_estimated_worktime
- if policy(@exercise).detailed_statistics?
@ -36,4 +36,5 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise))
= render('shared/pagination', collection: @feedbacks)
script type="text/javascript" $(function () { $('[data-bs-toggle="tooltip"]').tooltip() });
= javascript_tag nonce: true do
| $(function () { $('[data-bs-toggle="tooltip"]').tooltip() });

View File

@ -1,24 +1,32 @@
h1 = ExternalUser.model_name.human(count: 2)
= render(layout: 'shared/form_filters') do |f|
.col-md-9.col
.row.align-items-center
.col
= f.label(:name_cont, t('activerecord.attributes.external_user.name'), class: 'visually-hidden form-label')
= f.search_field(:name_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.name'))
.col.mt-0.mt-sm-3.mt-md-0
= f.label(:email_cont, t('activerecord.attributes.external_user.email'), class: 'visually-hidden form-label')
= f.search_field(:email_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.email'))
.col.mt-3.mt-lg-0
= f.label(:external_id_cont, t('activerecord.attributes.external_user.external_id'), class: 'visually-hidden form-label')
= f.search_field(:external_id_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.external_id'))
.row
.col-auto
= f.label(:role_eq, t('activerecord.attributes.external_user.role'), class: 'visually-hidden form-label')
= f.select(:role_eq, User::ROLES.map { |role| [t("users.roles.#{role}"), role] }, { include_blank: true }, class: 'form-control', prompt: t('activerecord.attributes.external_user.role'))
.col-auto.mt-3.mt-lg-0
= f.label(:consumer_id_eq, t('activerecord.attributes.external_user.consumer'), class: 'visually-hidden form-label')
= f.collection_select(:consumer_id_eq, Consumer.with_external_users, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.external_user.consumer'))
- if current_user.admin?
.col-md-9.col
.row.align-items-center
.col
= f.label(:name_cont, t('activerecord.attributes.external_user.name'), class: 'visually-hidden form-label')
= f.search_field(:name_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.name'))
.col.mt-0.mt-sm-3.mt-md-0
= f.label(:email_cont, t('activerecord.attributes.external_user.email'), class: 'visually-hidden form-label')
= f.search_field(:email_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.email'))
.col.mt-3.mt-lg-0
= f.label(:external_id_cont, t('activerecord.attributes.external_user.external_id'), class: 'visually-hidden form-label')
= f.search_field(:external_id_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.external_id'))
.row
.col-auto
= f.label(:role_eq, t('activerecord.attributes.external_user.role'), class: 'visually-hidden form-label')
= f.select(:role_eq, User::ROLES.map { |role| [t("users.roles.#{role}"), role] }, { include_blank: true }, class: 'form-control', prompt: t('activerecord.attributes.external_user.role'))
.col-auto.mt-3.mt-lg-0
= f.label(:consumer_id_eq, t('activerecord.attributes.external_user.consumer'), class: 'visually-hidden form-label')
= f.collection_select(:consumer_id_eq, Consumer.with_external_users, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.external_user.consumer'))
- else
.col-auto
= f.label(:name_cont, t('activerecord.attributes.external_user.name'), class: 'visually-hidden form-label')
= f.search_field(:name_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.name'))
.col-auto
= f.label(:external_id_cont, t('activerecord.attributes.external_user.external_id'), class: 'visually-hidden form-label')
= f.search_field(:external_id_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.external_id'))
.table-responsive
table.table
thead

View File

@ -9,14 +9,14 @@ html lang="#{I18n.locale || I18n.default_locale}"
= favicon_link_tag('/favicon.png', type: 'image/png')
= favicon_link_tag('/favicon.png', rel: 'apple-touch-icon', type: 'image/png')
= action_cable_meta_tag
= stylesheet_pack_tag('application', 'stylesheets', media: 'all', 'data-turbolinks-track': true)
= stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track': true)
= javascript_pack_tag('application', 'data-turbolinks-track': true, defer: false)
= javascript_include_tag('application', 'data-turbolinks-track': true)
= stylesheet_pack_tag('application', 'stylesheets', media: 'all', 'data-turbolinks-track': true, integrity: true, crossorigin: 'anonymous')
= stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track': true, integrity: true, crossorigin: 'anonymous')
= javascript_pack_tag('application', 'data-turbolinks-track': true, defer: false, integrity: true, crossorigin: 'anonymous')
= javascript_include_tag('application', 'data-turbolinks-track': true, integrity: true, crossorigin: 'anonymous')
= yield(:head)
= csrf_meta_tags
= timeago_script_tag
script type="text/javascript"
= timeago_script_tag nonce: true
= javascript_tag nonce: true do
| I18n.defaultLocale = "#{I18n.default_locale}";
| I18n.locale = "#{I18n.locale}";
- if SentryJavascript.active?

View File

@ -1,5 +0,0 @@
# frozen_string_literal: true
json.set! :files do
json.array! @exercise.files.visible, :content, :id
end

View File

@ -79,7 +79,7 @@
= render('shared/modal', id: 'comment-modal', title: t('exercises.implement.comment.dialogtitle'), template: 'exercises/_comment_dialogcontent')
javascript:
javascript [nonce=content_security_policy_nonce]:
$('.modal-content').draggable({
handle: '.modal-header'

View File

@ -0,0 +1,18 @@
default: &default
default_src: []
development:
<<: *default
# Allow the webpack-dev-server in development
connect_src:
- http://localhost:3035
- ws://localhost:3035
production:
<<: *default
test:
<<: *default

View File

@ -0,0 +1,33 @@
# This file allows to further customize the Content Security Policy (CSP)
# All settings will be applied **in addition** to the application CSP
# Default directives are defined here: `initializers/content_security_policy.rb`
default: &default
# Allow the S3 service hosted by the openHPI Cloud to be used for images
img_src:
- https://s3.xopic.de
- https://*.s3.xopic.de
- https://s3.openhpicloud.de
- https://*.s3.openhpicloud.de
# Webkit didn't consider the WSS scheme as part of 'self', adding it explicitly
# See https://bugs.webkit.org/show_bug.cgi?id=235873
connect_src:
- wss://codeocean.openhpi.de
# Optionally: Specify a custom, non-Sentry URL for reporting CSP violations
# report_uri: https://example.com/csp-report
development:
<<: *default
# Allow the webpack-dev-server in development
connect_src:
- http://localhost:3035
- ws://localhost:3035
production:
<<: *default
test:
<<: *default

View File

@ -38,7 +38,7 @@ Rails.application.configure do
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options).
config.active_storage.service = :local
@ -50,6 +50,7 @@ Rails.application.configure do
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
config.ssl_options = {hsts: {preload: true}}
# Include generic and useful information about system operation, but avoid logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII).

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'active_support/core_ext/integer/time'
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
@ -9,18 +11,15 @@ Rails.application.configure do
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# true: Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
# Eager load code for prometheus exporter
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
# Eager load is also required for the prometheus exporter
config.eager_load = true
# enable web console in staging
config.web_console.development_only = false
# Show full error reports and disable caching.
config.consider_all_requests_local = true
# Full error reports as well as caching are disabled.
config.consider_all_requests_local = false
config.action_controller.perform_caching = false
# Raise an error on page load if there are pending migrations.
@ -39,47 +38,50 @@ Rails.application.configure do
# For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
# config.action_dispatch.rack_cache = true
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
# Compress JavaScripts and CSS.
# config.assets.js_compressor = :uglifier
# Compress CSS using a preprocessor.
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Generate digests for assets URLs.
config.assets.digest = true
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.asset_host = 'http://assets.example.com'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options).
config.active_storage.service = :local
# Mount Action Cable outside main process or domain.
# config.action_cable.mount_path = nil
# config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
config.ssl_options = {hsts: {preload: true}}
# Set to :debug to see everything in the log.
# Include generic and useful information about system operation, but avoid logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII).
config.log_level = :info
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
# Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# config.log_tags = [ :subdomain, :uuid, :request_id ]
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = "http://assets.example.com"
# Use a real queuing backend for Active Job (and separate queues per environment).
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "code_ocean_production"
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# config.assets.precompile += %w( search.js )
config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
@ -92,12 +94,46 @@ Rails.application.configure do
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Disable automatic flushing of the log to improve performance.
# config.autoflush_log = false
# Log disallowed deprecations.
config.active_support.disallowed_deprecation = :log
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV['RAILS_LOG_TO_STDOUT'].present?
logger = ActiveSupport::Logger.new($stdout)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
# Inserts middleware to perform automatic connection switching.
# The `database_selector` hash is used to pass options to the DatabaseSelector
# middleware. The `delay` is used to determine how long to wait after a write
# to send a subsequent read to the primary.
#
# The `database_resolver` class is used by the middleware to determine which
# database is appropriate to use based on the time delay.
#
# The `database_resolver_context` class is used by the middleware to set
# timestamps for the last write to the primary. The resolver uses the context
# class timestamps to determine how long to wait before reading from the
# replica.
#
# By default Rails will store a last write timestamp in the session. The
# DatabaseSelector middleware is designed as such you can define your own
# strategy for connection switching and pass that into the middleware through
# these configuration options.
# config.active_record.database_selector = { delay: 2.seconds }
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end

View File

@ -6,28 +6,57 @@
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# Rails.application.config.content_security_policy do |policy|
# # If you are using webpack-dev-server then specify webpack-dev-server host
# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
require_relative 'sentry_csp'
require_relative 'sentry_javascript'
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
# policy.object_src :none
# policy.script_src :self, :https
# policy.style_src :self, :https
# # If you are using webpack-dev-server then specify webpack-dev-server host
# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
def self.apply_yml_settings_for(policy)
csp_settings = CodeOcean::Config.new(:content_security_policy)
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
# end
csp_settings.read.each do |directive, additional_settings|
existing_settings = if directive == 'report_uri'
''
else
policy.public_send(directive) || []
end
all_settings = existing_settings + additional_settings
policy.public_send(directive, *all_settings)
end
end
def self.apply_sentry_settings_for(policy)
sentry_domain = URI.parse SentryJavascript.dsn
additional_setting = "#{sentry_domain.scheme}://#{sentry_domain.host}"
existing_settings = policy.connect_src || []
all_settings = existing_settings + [additional_setting]
policy.connect_src(*all_settings)
end
Rails.application.config.content_security_policy do |policy|
policy.default_src :none
policy.base_uri :self
policy.font_src :self
# Code executions might return a base64 encoded image as a :data URI
policy.img_src :self, :data
policy.object_src :none
policy.script_src :self, :report_sample
# Our ACE editor unfortunately requires :unsafe_inline for the code highlighting
policy.style_src :self, :unsafe_inline, :report_sample
policy.connect_src :self
policy.form_action :self
policy.frame_ancestors :none
# Specify URI for violation reports
policy.report_uri SentryCsp.report_url if SentryCsp.active?
apply_yml_settings_for policy
apply_sentry_settings_for policy if SentryJavascript.active?
end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
Rails.application.config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
# Set the nonce only to specific directives
# Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
Rails.application.config.content_security_policy_nonce_directives = %w[script-src]
# Report CSP violations to a specified URI
# For further information see the following documentation:

View File

@ -1,12 +1,26 @@
# frozen_string_literal: true
# Define an application-wide HTTP permissions policy. For further
# information see https://developers.google.com/web/updates/2018/06/feature-policy
#
# Rails.application.config.permissions_policy do |f|
# f.camera :none
# f.gyroscope :none
# f.microphone :none
# f.usb :none
# f.fullscreen :self
# f.payment :self, "https://secure.example.com"
# end
# TODO: Feature-Policy has been renamed to Permissions-Policy. The Permissions-Policy is
# not yet supported by Rails (even though the new name is already used for the method)
Rails.application.config.permissions_policy do |policy|
policy.accelerometer :none
policy.ambient_light_sensor :none
policy.autoplay :none
policy.camera :none
policy.encrypted_media :none
policy.fullscreen :none
policy.geolocation :none
policy.gyroscope :none
policy.magnetometer :none
policy.microphone :none
policy.midi :none
policy.payment :none
policy.picture_in_picture :none
# The `speaker` directive is used for selection of non-default audio output devices
policy.speaker :none
policy.usb :none
policy.vibrate :none
policy.vr :none
end

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
require_relative 'sentry'
class SentryCsp
def self.active?
dsn.present? && %w[development test].exclude?(environment)
end
def self.report_url
parsed_url = URI.parse dsn
# Add additional variables to the query string
query_params = CGI.parse(parsed_url.query || '')
query_params[:sentry_release] = release if release
query_params[:sentry_environment] = environment if environment
# Add the query string back to the URL
parsed_url.query = URI.encode_www_form(query_params)
# Return the full URL
parsed_url.to_s
end
class << self
private
def dsn
ENV.fetch('SENTRY_CSP_REPORT_URL', nil)
end
def release
Sentry.configuration.release
end
def environment
Sentry.configuration.environment
end
end
end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
require_relative 'sentry'
class SentryJavascript
def self.active?
dsn.present? && %w[development test].exclude?(environment)

View File

@ -2,8 +2,23 @@
# Be sure to restart your server when you modify this file.
def self.cookie_prefix
if (Rails.env.production? || Rails.env.staging?) \
&& Rails.application.config.relative_url_root == '/'
'__Host-'
elsif Rails.env.production? || Rails.env.staging?
'__Secure-'
else
''
end
end
Rails.application.config.session_store :cookie_store,
key: '_code_ocean_session',
key: "#{cookie_prefix}CodeOcean-Session",
expire_after: 1.month,
secure: Rails.env.production? || Rails.env.staging?,
path: Rails.application.config.relative_url_root
path: Rails.application.config.relative_url_root,
# Signing in through LTI won't work with `SameSite=Strict`
# as the cookie is not sent when accessing the `implement` route
# following the LTI launch initiated by the LMS as a third party.
same_site: :lax

View File

@ -296,7 +296,7 @@ de:
form:
hints:
command: <em>filename</em> wird automatisch durch den richtigen Dateinamen ersetzt.
docker_image: 'Wählen Sie ein Docker-Image aus der Liste oder fügen Sie ein neues hinzu, welches über <a href="https://hub.docker.com/" target="_blank">DockerHub</a> verfügbar ist.'
docker_image: 'Wählen Sie ein Docker-Image aus der Liste oder fügen Sie ein neues hinzu, welches über <a href="https://hub.docker.com/" target="_blank" rel="noopener">DockerHub</a> verfügbar ist.'
exposed_ports_list: Während der Ausführung sind diese Ports für den Nutzer zugänglich. Die Portnummern müssen nummerisch und mit Komma voneinander getrennt sein.
cpu_limit: Geben Sie die Mindestmenge an CPU-Anteilen an, die für jeden Runner reserviert werden soll, gemessen in MHz.
errors:
@ -340,7 +340,7 @@ de:
expand_output_sidebar: Ausgabe-Leiste Ausklappen
input: Ihre Eingabe
lastsaved: 'Zuletzt gespeichert: '
network: 'Während Ihr Code läuft, ist Port %{port} unter folgender Adresse erreichbar: <a href="%{address}" target="_blank">%{address}</a>.'
network: 'Während Ihr Code läuft, ist Port %{port} unter folgender Adresse erreichbar: <a href="%{address}" target="_blank" rel="noopener">%{address}</a>.'
render: Anzeigen
run: Ausführen
run_failure: Ihr Code konnte nicht auf der Plattform ausgeführt werden.
@ -453,7 +453,7 @@ de:
request: "Kommentaranfrage stellen"
question: "Bitte beschreiben Sie kurz Ihre Probleme oder nennen Sie den Programmteil, zu dem Sie Feedback wünschen. Ihr Programmcode und eventuelle Fehlermeldungen werden automatisch zur Anfrage hinzugefügt."
intervention:
explanation: "Diese Meldung erscheint, weil Sie %{duration} Minuten an dieser Aufgabe gearbeitet haben. 25% Ihrer Mitlernenden arbeiten länger daran, insofern ist das kein Problem, aber dies hat sich als <a href='https://hpi.de/forschung/publikationen/dissertationen/dissertation-ralf-teusner.html' style='display: contents;'>effektiven Zeitpunkt für diese Meldung</a> erwiesen."
explanation: "Diese Meldung erscheint, weil Sie %{duration} Minuten an dieser Aufgabe gearbeitet haben. 25% Ihrer Mitlernenden arbeiten länger daran, insofern ist das kein Problem, aber dies hat sich als <a href='https://hpi.de/forschung/publikationen/dissertationen/dissertation-ralf-teusner.html' style='display: contents;' target='_blank' rel='noopener'>effektiven Zeitpunkt für diese Meldung</a> erwiesen."
rfc_intervention:
text: "Falls Sie bei dieser Aufgabe nicht weiterkommen und nicht selbst weiter knobeln möchten, können Ihre Mitlernenden bestimmt helfen! </br> </br>"
break_intervention:
@ -780,7 +780,7 @@ de:
runtime_output: "Programmausgabe"
test_results: "Testergebnisse"
sessions:
expired: Ihre Session ist abgelaufen. Bitte <a href="javascript:window.location.reload(true)">laden Sie diese Seite neu</a> bevor Sie fortfahren.
expired: Ihre Session ist abgelaufen. Bitte <a href="" class="reloadCurrentPage">laden Sie diese Seite neu</a> bevor Sie fortfahren.
create:
failure: Fehlerhafte E-Mail oder Passwort.
success: Sie haben sich erfolgreich angemeldet.
@ -793,7 +793,7 @@ de:
destroy_through_lti:
average_score: Durchschnittliche Punktzahl
final_submissions: Abgaben anderer Nutzer
finished_with_consumer: 'Sie können dieses Fenster nun schließen oder <a href="%{url}">zu %{consumer} zurückkehren</a>.'
finished_with_consumer: 'Sie können dieses Fenster nun schließen oder <a href="%{url}" rel="nofollow">zu %{consumer} zurückkehren</a>.'
finished_without_consumer: Sie können dieses Fenster nun schließen.
headline: Gut gemacht!
score: Ihre Punktzahl
@ -834,7 +834,7 @@ de:
link: Hilfe
index: Index
message_failure: Leider ist ein Fehler auf unserer Plattform aufgetreten. Bitte probieren Sie es später noch einmal.
websocket_failure: Leider ist ein Verbindungsproblem aufgetreten. <a href="https://websocketstest.com">Bitte überprüfen Sie Websocket-Verbindungen mit diesem Tool</a> und versuchen Sie es erneut.
websocket_failure: Leider ist ein Verbindungsproblem aufgetreten. <a href="https://websocketstest.com" target="_blank" rel="noopener">Bitte überprüfen Sie Websocket-Verbindungen mit diesem Tool</a> und versuchen Sie es erneut.
new: Hinzufügen
new_model: '%{model} hinzufügen'
number: Nummer

View File

@ -296,7 +296,7 @@ en:
form:
hints:
command: <em>filename</em> is automatically replaced with the correct filename.
docker_image: Pick a Docker image listed above or add a new one which is available via <a href="https://hub.docker.com/" target="_blank">DockerHub</a>.
docker_image: Pick a Docker image listed above or add a new one which is available via <a href="https://hub.docker.com/" target="_blank" rel="noopener">DockerHub</a>.
exposed_ports_list: During code execution these ports are accessible for the user. Port numbers must be numeric and separated by a comma.
cpu_limit: Specify the minimum amount of CPU shares to reserve for each runner, measured in MHz.
errors:
@ -340,7 +340,7 @@ en:
expand_output_sidebar: Expand Output Sidebar
input: Your input
lastsaved: 'Last saved: '
network: 'While your code is running, port %{port} is accessible using the following address: <a href="%{address}" target="_blank">%{address}</a>.'
network: 'While your code is running, port %{port} is accessible using the following address: <a href="%{address}" target="_blank" rel="noopener">%{address}</a>.'
render: Render
run: Run
run_failure: Your code could not be run.
@ -453,7 +453,7 @@ en:
request: "Request Comments"
question: 'Please shortly describe your problem or the program part you would like to get feedback for. Your program code and potential error messages are automatically appended to your request.'
intervention:
explanation: "This message appears because you have been working on this exercise for %{duration} minutes. 25% of your fellow learners took more time to solve the exercise, so in that sense it's not a problem, but this has proven to be an <a href='https://hpi.de/en/research/publications/dissertations/dissertation-ralf-teusner.html' style='display: contents;'>effective time for this message</a>."
explanation: "This message appears because you have been working on this exercise for %{duration} minutes. 25% of your fellow learners took more time to solve the exercise, so in that sense it's not a problem, but this has proven to be an <a href='https://hpi.de/en/research/publications/dissertations/dissertation-ralf-teusner.html' style='display: contents;' target='_blank' rel='noopener'>effective time for this message</a>."
rfc_intervention:
text: "If you are struggling with this exercise and don't want to continue on your own, your fellow learners can help out! </br> </br>"
break_intervention:
@ -780,7 +780,7 @@ en:
runtime_output: "Runtime Output"
test_results: "Test Results"
sessions:
expired: Your session has expired. Please <a href="javascript:window.location.reload(true)">reload this page</a> before continuing.
expired: Your session has expired. Please <a href="" class="reloadCurrentPage">reload this page</a> before continuing.
create:
failure: Invalid email or password.
success: Successfully signed in.
@ -793,7 +793,7 @@ en:
destroy_through_lti:
average_score: Average Score
final_submissions: Other Users' Submissions
finished_with_consumer: 'You may close this window now or <a href="%{url}">return to %{consumer}</a>.'
finished_with_consumer: 'You may close this window now or <a href="%{url}" rel="nofollow">return to %{consumer}</a>.'
finished_without_consumer: You may close this window now.
headline: Well done!
score: Your Score
@ -834,7 +834,7 @@ en:
link: Help
index: Index
message_failure: 'Sorry, something went wrong.'
websocket_failure: Sorry, a connection issue occoured. <a href="https://websocketstest.com">Please check WebSocket connections with this tool</a> and try again.
websocket_failure: Sorry, a connection issue occoured. <a href="https://websocketstest.com" target="_blank" rel="noopener">Please check WebSocket connections with this tool</a> and try again.
new: Add
new_model: 'Add %{model}'
number: Number

View File

@ -128,6 +128,7 @@ Rails.application.routes.draw do
namespace :code_ocean do
resources :files, only: %i[create destroy]
end
get '/uploads/files/:id/:filename', to: 'code_ocean/files#show_protected_upload', as: :protected_upload, constraints: {filename: FILENAME_REGEXP}
resources :file_types

View File

@ -1,12 +1,14 @@
// See the shakacode/shakapacker README and docs directory for advice on customizing your webpackConfig.
const { webpackConfig, merge } = require('shakapacker')
const { webpackConfig, config, merge } = require('shakapacker')
const webpack = require('webpack');
const CompressionPlugin = require("compression-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const WebpackAssetsManifest = require('webpack-assets-manifest');
const { SubresourceIntegrityPlugin } = require("webpack-subresource-integrity");
// Custom ERB loader to disable Spring and prevent crashes
const erb = require("./loaders/erb");
@ -30,7 +32,9 @@ const envConfig = module.exports = {
],
},
output: {
publicPath: relative_url_root + public_output_path
publicPath: relative_url_root + public_output_path,
// the following setting is required for SRI to work:
crossOriginLoading: 'anonymous',
},
performance: {
// Turn off size warnings for large assets
@ -53,6 +57,15 @@ const envConfig = module.exports = {
}),
new CompressionPlugin(),
new MiniCssExtractPlugin(),
new SubresourceIntegrityPlugin(),
new WebpackAssetsManifest({
entrypoints: true,
integrity: false,
writeToDisk: true,
entrypointsUseAssets: true,
publicPath: true,
output: config.manifestPath,
})
],
resolve: {
extensions: ['.css', '.ts', '.tsx'],
@ -65,4 +78,8 @@ const envConfig = module.exports = {
stats: 'minimal',
}
// Use the two lines below to remove the original WebpackAssetsManifest and replace it with our custom config.
const filteredPlugins = webpackConfig.plugins.filter((plugin) => !(plugin instanceof WebpackAssetsManifest))
webpackConfig.plugins = filteredPlugins;
module.exports = merge(webpackConfig, envConfig)

View File

@ -194,7 +194,7 @@ source "$HOME/.profile"
- Create all necessary config files:
```bash
for f in action_mailer.yml database.yml secrets.yml code_ocean.yml docker.yml.erb mnemosyne.yml
for f in action_mailer.yml database.yml secrets.yml code_ocean.yml docker.yml.erb mnemosyne.yml content_security_policy.yml
do
if [ ! -f config/$f ]
then
@ -303,7 +303,7 @@ source "$HOME/.profile"
```
- Get a local copy of the config files and verify the settings:
```shell script
for f in action_mailer.yml database.yml secrets.yml code_ocean.yml docker.yml.erb mnemosyne.yml
for f in action_mailer.yml database.yml secrets.yml code_ocean.yml docker.yml.erb mnemosyne.yml content_security_policy.yml
do
if [ ! -f config/$f ]
then

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module Webpacker::SriHelperExtensions
def stylesheet_link_tag(*sources, **options)
tags = sources.map do |stylesheet|
if stylesheet.is_a?(Hash)
super(stylesheet[:src], options.merge(integrity: stylesheet[:integrity]))
else
super(stylesheet, options)
end
end
safe_join(tags)
end
def javascript_include_tag(*sources, **options)
tags = sources.map do |javascript|
if javascript.is_a?(Hash)
super(javascript[:src], options.merge(integrity: javascript[:integrity]))
else
super(javascript, options)
end
end
safe_join(tags)
end
end
Sprockets::Rails::Helper.prepend(Webpacker::SriHelperExtensions)

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
module Webpacker::SriManifestExtensions
def lookup(name, pack_type = {})
asset = super
augment_with_integrity asset, pack_type
end
def lookup_pack_with_chunks(name, pack_type = {})
assets = super
assets.map do |asset|
augment_with_integrity asset, pack_type
end
end
def augment_with_integrity(asset, _pack_type = {})
if asset.respond_to?(:dig) && asset['integrity']
{src: asset['src'], integrity: asset['integrity']}
elsif asset.respond_to?(:dig)
asset['src']
else
asset
end
end
end
Webpacker::Manifest.prepend(Webpacker::SriManifestExtensions)

View File

@ -2,17 +2,17 @@
"name": "codeocean",
"private": true,
"dependencies": {
"@babel/core": "^7.18.10",
"@babel/core": "^7.19.0",
"@babel/plugin-transform-runtime": "^7.18.10",
"@babel/preset-env": "7",
"@babel/runtime": "7",
"@egjs/hammerjs": "^2.0.17",
"@fortawesome/fontawesome-free": "^6.1.2",
"@fortawesome/fontawesome-free": "^6.2.0",
"@popperjs/core": "^2.11.6",
"@sentry/browser": "^6.11.0",
"@sentry/browser": "^7.11.1",
"@webpack-cli/serve": "^1.7.0",
"babel-loader": "^8.2.5",
"bootstrap": "^5.2.0",
"bootstrap": "^5.2.1",
"bootswatch": "^5.2.0",
"chosen-js": "^1.8.7",
"component-emitter": "^1.3.0",
@ -22,8 +22,8 @@
"d3": "^7.6.1",
"d3-tip": "^0.9.1",
"highlight.js": "^11.5.1",
"i18n-js": "^4.0.2",
"jquery": "^3.6.0",
"i18n-js": "^4.1.1",
"jquery": "^3.6.1",
"jquery-ui": "^1.13.1",
"jquery-ujs": "^1.2.3",
"jstree": "^3.3.12",
@ -34,13 +34,13 @@
"pnp-webpack-plugin": "^1.7.0",
"propagating-hammerjs": "^2.0.1",
"rails-erb-loader": "^5.5.2",
"sass": "^1.54.4",
"sass": "^1.54.9",
"sass-loader": "^13.0.2",
"shakapacker": "6.5.1",
"shakapacker": "6.5.2",
"sortablejs": "^1.15.0",
"sorttable": "^1.0.2",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.5",
"terser-webpack-plugin": "^5.3.6",
"underscore": "^1.13.4",
"uuid": "^8.3.2",
"vis-data": "^7.1.4",
@ -51,10 +51,11 @@
"webpack-cli": "^4.10.0",
"webpack-merge": "^5.8.0",
"webpack-sources": "^3.2.3",
"webpack-subresource-integrity": "^5.1.0",
"xss": "^1.0.14"
},
"devDependencies": {
"webpack-dev-server": "^4.10.0"
"webpack-dev-server": "^4.11.0"
},
"babel": {
"presets": [

View File

@ -92,7 +92,7 @@ gem install bundler
cd /home/vagrant/codeocean
# config
for f in action_mailer.yml database.yml secrets.yml docker.yml.erb mnemosyne.yml
for f in action_mailer.yml database.yml secrets.yml docker.yml.erb mnemosyne.yml content_security_policy.yml
do
if [ ! -f config/$f ]
then

View File

@ -25,6 +25,8 @@ describe FileParameters do
it 'new file' do
submission = create(:submission, exercise: hello_world, id: 1337)
controller.instance_variable_set(:@current_user, submission.user)
new_file = create(:file, context: submission)
expect(file_accepted?(new_file)).to be true
end
@ -42,16 +44,27 @@ describe FileParameters do
expect(file_accepted?(hidden_file)).to be false
end
it 'read only file' do
it 'read-only file' do
read_only_file = create(:file, context: hello_world, read_only: true)
expect(file_accepted?(read_only_file)).to be false
end
it 'non existent file' do
it 'non-existent file' do
# Ensure to use an invalid id for the file.
non_existent_file = build(:file, context: hello_world, id: -1)
expect(file_accepted?(non_existent_file)).to be false
end
it 'file of another submission' do
learner1 = create(:learner)
learner2 = create(:learner)
submission_learner1 = create(:submission, exercise: hello_world, user: learner1)
_submission_learner2 = create(:submission, exercise: hello_world, user: learner2)
controller.instance_variable_set(:@current_user, learner2)
other_submissions_file = create(:file, context: submission_learner1)
expect(file_accepted?(other_submissions_file)).to be false
end
end
end
end

View File

@ -7,6 +7,26 @@ describe CodeOcean::FilesController do
before { allow(controller).to receive(:current_user).and_return(user) }
describe 'GET #show_protected_upload' do
context 'with a valid filename' do
let(:submission) { create(:submission, exercise: create(:audio_video)) }
before { get :show_protected_upload, params: {filename: file.name_with_extension, id: file.id} }
context 'with a binary file' do
let(:file) { submission.collect_files.detect {|file| file.file_type.file_extension == '.mp4' } }
expect_assigns(file: :file)
expect_content_type('video/mp4')
expect_http_status(:ok)
it 'sets the correct filename' do
expect(response.headers['Content-Disposition']).to include("attachment; filename=\"#{file.name_with_extension}\"")
end
end
end
end
describe 'POST #create' do
let(:submission) { create(:submission, user: user) }

View File

@ -6,7 +6,10 @@ describe ExercisesController do
let(:exercise) { create(:dummy) }
let(:user) { create(:admin) }
before { allow(controller).to receive(:current_user).and_return(user) }
before do
create(:test_file, context: exercise)
allow(controller).to receive(:current_user).and_return(user)
end
describe 'PUT #batch_update' do
let(:attributes) { {public: 'true'} }
@ -184,6 +187,17 @@ describe ExercisesController do
expect_flash_message(:alert, :'exercises.implement.no_files')
expect_redirect(:exercise)
end
context 'with other users accessing an unpublished exercise' do
let(:exercise) { create(:fibonacci, unpublished: true) }
let(:user) { create(:teacher) }
before { perform_request.call }
expect_assigns(exercise: :exercise)
expect_flash_message(:alert, :'exercises.implement.unpublished')
expect_redirect(:exercise)
end
end
describe 'GET #index' do
@ -220,6 +234,8 @@ describe ExercisesController do
describe 'GET #reload' do
context 'when being anyone' do
let(:exercise) { create(:fibonacci) }
before { get :reload, format: :json, params: {id: exercise.id} }
expect_assigns(exercise: :exercise)

View File

@ -74,11 +74,9 @@ describe SubmissionsController do
expect_assigns(file: :file)
expect_assigns(submission: :submission)
expect_content_type('video/mp4')
expect_http_status(:ok)
it 'sets the correct filename' do
expect(response.headers['Content-Disposition']).to include("attachment; filename=\"#{file.name_with_extension}\"")
it 'sets the correct redirect' do
expect(response.location).to eq protected_upload_url(id: file, filename: file.name_with_extension)
end
end

View File

@ -78,6 +78,25 @@ describe 'Authentication' do
expect(page).to have_content(I18n.t('application.not_authorized'))
end
end
context 'when the authentication token is used to login' do
let(:token) { create(:authentication_token, user: user) }
it 'invalidates the token on login' do
mail.deliver_now
visit(rfc_link)
expect(token.reload.expire_at).to be_within(10.seconds).of(Time.zone.now)
end
it 'does not allow a second login' do
mail.deliver_now
visit(rfc_link)
expect(page).to have_current_path(rfc_link)
visit(sign_out_path)
visit(rfc_link)
expect(page).to have_current_path(root_path)
end
end
end
end

View File

@ -23,6 +23,7 @@ describe 'Editor', js: true do
}]
end
let(:user) { create(:teacher) }
let(:exercise_without_test) { create(:tdd) }
before do
visit(sign_in_path)
@ -93,12 +94,28 @@ describe 'Editor', js: true do
end
end
context 'when an exercise has one or more teacher-defined assessments' do
it 'displays the score button' do
visit(implement_exercise_path(exercise))
expect(page).to have_content(exercise.title)
expect(page).to have_content(I18n.t('exercises.editor.score'))
end
end
context 'when an exercise has no teacher-defined assessment' do
it 'disables the score button' do
visit(implement_exercise_path(exercise_without_test))
expect(page).to have_content(exercise_without_test.title)
expect(page).not_to have_content(I18n.t('exercises.editor.score'))
end
end
it 'contains a button for submitting the exercise' do
submission = build(:submission, user: user, exercise: exercise)
allow(submission).to receive(:calculate_score).and_return(scoring_response)
allow(Submission).to receive(:find).and_return(submission)
click_button(I18n.t('exercises.editor.score'))
expect(page).not_to have_css('#submit_outdated')
expect(page).to have_css('#submit')
expect(page).not_to have_content(I18n.t('exercises.editor.tooltips.exercise_deadline_passed'))
expect(page).to have_content(I18n.t('exercises.editor.submit'))
end
end

View File

@ -93,6 +93,25 @@ describe UserMailer do
# A five minute tolerance is allowed to account for the time difference between `now` and the creation timestamp of the token.
expect(token.expire_at - Time.zone.now).to be_within(5.minutes).of(7.days)
end
it 'sets the correct comment' do
expect(mail.body).to include(request_for_comment.comments.first.text)
end
context 'with an HTML comment' do
let(:html_comment) { '<b>test</b>' }
let(:escaped_comment) { '&lt;b&gt;test&lt;/b&gt;' }
before { request_for_comment.comments.first.update(text: html_comment) }
it 'does not include the HTML tags' do
expect(mail.body).not_to include(html_comment)
end
it 'includes escaped HTML tags' do
expect(mail.body).to include(escaped_comment)
end
end
end
describe '#got_new_comment_for_subscription' do
@ -128,21 +147,40 @@ describe UserMailer do
# A five minute tolerance is allowed to account for the time difference between `now` and the creation timestamp of the token.
expect(token.expire_at - Time.zone.now).to be_within(5.minutes).of(7.days)
end
it 'sets the correct comment' do
expect(mail.body).to include(request_for_comment.comments.first.text)
end
context 'with an HTML comment' do
let(:html_comment) { '<b>test</b>' }
let(:escaped_comment) { '&lt;b&gt;test&lt;/b&gt;' }
before { request_for_comment.comments.first.update(text: html_comment) }
it 'does not include the HTML tags' do
expect(mail.body).not_to include(html_comment)
end
it 'includes escaped HTML tags' do
expect(mail.body).to include(escaped_comment)
end
end
end
describe '#send_thank_you_note' do
let(:user) { create(:learner) }
let(:token) { AuthenticationToken.find_by(user: user) }
let(:request_for_comments) { create(:rfc_with_comment, user: user) }
let(:receiver) { InternalUser.create(attributes_for(:teacher)) }
let(:mail) { described_class.send_thank_you_note(request_for_comments, receiver).deliver_now }
let(:receiver) { create(:teacher) }
let(:token) { AuthenticationToken.find_by(user: receiver) }
let(:request_for_comment) { create(:rfc_with_comment, user: user) }
let(:mail) { described_class.send_thank_you_note(request_for_comment, receiver).deliver_now }
it 'sets the correct sender' do
expect(mail.from).to include('codeocean@hpi.de')
end
it 'sets the correct subject' do
expect(mail.subject).to eq(I18n.t('mailers.user_mailer.send_thank_you_note.subject', author: request_for_comments.user.displayname))
expect(mail.subject).to eq(I18n.t('mailers.user_mailer.send_thank_you_note.subject', author: request_for_comment.user.displayname))
end
it 'sets the correct receiver' do
@ -150,7 +188,7 @@ describe UserMailer do
end
it 'includes the correct URL' do
expect(mail.body).to include(request_for_comment_url(request_for_comments, token: token.shared_secret))
expect(mail.body).to include(request_for_comment_url(request_for_comment, token: token.shared_secret))
end
it 'creates a new authentication token' do
@ -162,5 +200,24 @@ describe UserMailer do
# A five minute tolerance is allowed to account for the time difference between `now` and the creation timestamp of the token.
expect(token.expire_at - Time.zone.now).to be_within(5.minutes).of(7.days)
end
it 'sets the correct thank_you_note' do
expect(mail.body).to include(request_for_comment.thank_you_note)
end
context 'with an HTML comment' do
let(:html_comment) { '<b>test</b>' }
let(:escaped_comment) { '&lt;b&gt;test&lt;/b&gt;' }
before { request_for_comment.update(thank_you_note: html_comment) }
it 'does not include the HTML tags' do
expect(mail.body).not_to include(html_comment)
end
it 'includes escaped HTML tags' do
expect(mail.body).to include(escaped_comment)
end
end
end
end

View File

@ -69,7 +69,27 @@ describe CodeOcean::File do
end
context 'when the path has been modified' do
before { file.update(native_file: '../../../../secrets.yml') }
before do
file.update_column(:native_file, '../../../../secrets.yml') # rubocop:disable Rails/SkipsModelValidations
file.reload
end
it 'does not read the native file' do
expect(file.read).not_to be_present
end
end
context 'when a symlink is used' do
let(:fake_upload_location) { File.join(CarrierWave::Uploader::Base.new.root, 'uploads', 'files', 'secrets.yml') }
before do
FileUtils.touch Rails.root.join('config/secrets.yml')
File.symlink Rails.root.join('config/secrets.yml'), fake_upload_location
file.update_column(:native_file, '../secrets.yml') # rubocop:disable Rails/SkipsModelValidations
file.reload
end
after { File.delete(fake_upload_location) }
it 'does not read the native file' do
expect(file.read).not_to be_present

View File

@ -124,4 +124,41 @@ describe Exercise do
expect(exercise.duplicate).to be_a(described_class)
end
end
describe '#teacher_defined_assessment?' do
let(:exercise) { create(:dummy) }
context 'when no assessment is defined' do
it 'returns false' do
expect(exercise).not_to be_teacher_defined_assessment
end
end
context 'when unit tests are defined' do
before { create(:test_file, context: exercise) }
it 'returns true' do
expect(exercise).to be_teacher_defined_assessment
end
end
context 'when linter tests are defined' do
before { create(:test_file, context: exercise, role: 'teacher_defined_linter') }
it 'returns true' do
expect(exercise).to be_teacher_defined_assessment
end
end
context 'when unit and linter tests are defined' do
before do
create(:test_file, context: exercise)
create(:test_file, context: exercise, role: 'teacher_defined_linter')
end
it 'returns true' do
expect(exercise).to be_teacher_defined_assessment
end
end
end
end

View File

@ -54,7 +54,7 @@ describe CodeharborLinkPolicy do
end
end
permissions(:enabled?) do
permissions :enabled? do
it 'reflects the config option' do
%i[external_user admin teacher].each do |factory_name|
expect(policy).to permit(create(factory_name), codeharbor_link)
@ -72,7 +72,7 @@ describe CodeharborLinkPolicy do
allow(codeocean_config).to receive(:read).and_return(codeharbor_config)
end
permissions(:enabled?) do
permissions :enabled? do
it 'reflects the config option' do
%i[external_user admin teacher].each do |factory_name|
expect(policy).not_to permit(create(factory_name), codeharbor_link)

View File

@ -7,19 +7,17 @@ describe ExecutionEnvironmentPolicy do
let(:execution_environment) { build(:ruby) }
[:index?].each do |action|
permissions(action) do
it 'grants access to admins' do
expect(policy).to permit(build(:admin), execution_environment)
end
permissions :index? do
it 'grants access to admins' do
expect(policy).to permit(build(:admin), execution_environment)
end
it 'grants access to teachers' do
expect(policy).to permit(build(:teacher), execution_environment)
end
it 'grants access to teachers' do
expect(policy).to permit(build(:teacher), execution_environment)
end
it 'does not grant access to external users' do
expect(policy).not_to permit(build(:external_user), execution_environment)
end
it 'does not grant access to external users' do
expect(policy).not_to permit(build(:external_user), execution_environment)
end
end
@ -59,7 +57,7 @@ describe ExecutionEnvironmentPolicy do
end
end
permissions(:sync_all_to_runner_management?) do
permissions :sync_all_to_runner_management? do
it 'grants access to the admin' do
expect(policy).to permit(build(:admin))
end

View File

@ -104,19 +104,79 @@ describe ExercisePolicy do
end
end
[:show?].each do |action|
permissions :show? do
it 'not grants access to external users' do
expect(policy).not_to permit(build(:external_user), exercise)
end
end
%i[implement? working_times? intervention? search? reload?].each do |action|
permissions(action) do
it 'not grants access to external users' do
expect(policy).not_to permit(build(:external_user), exercise)
context 'when the exercise has no visible files' do
let(:exercise) { create(:dummy) }
it 'does not grant access to anyone' do
%i[admin external_user teacher].each do |factory_name|
expect(policy).not_to permit(build(factory_name), exercise)
end
end
end
context 'when the exercise has visible files' do
let(:exercise) { create(:fibonacci) }
it 'grants access to anyone' do
%i[admin external_user teacher].each do |factory_name|
expect(policy).to permit(build(factory_name), exercise)
end
end
end
context 'when the exercise is published' do
let(:exercise) { create(:fibonacci, unpublished: false) }
it 'grants access to anyone' do
%i[admin external_user teacher].each do |factory_name|
expect(policy).to permit(build(factory_name), exercise)
end
end
end
context 'when the exercise is unpublished' do
let(:exercise) { create(:fibonacci, unpublished: true) }
it 'grants access to admins' do
expect(policy).to permit(build(:admin), exercise)
end
it 'grants access to the author' do
expect(policy).to permit(exercise.author, exercise)
end
it 'does not grant access to everyone' do
%i[external_user teacher].each do |factory_name|
expect(policy).not_to permit(build(factory_name), exercise)
end
end
end
end
end
%i[implement? submit?].each do |action|
permissions(action) do
permissions :submit? do
context 'when teacher-defined assessments are available' do
before { create(:test_file, context: exercise) }
it 'grants access to anyone' do
%i[admin external_user teacher].each do |factory_name|
expect(policy).to permit(build(factory_name), Exercise.new)
expect(policy).to permit(build(factory_name), exercise)
end
end
end
context 'when teacher-defined assessments are not available' do
it 'does not grant access to anyone' do
%i[admin external_user teacher].each do |factory_name|
expect(policy).not_to permit(build(factory_name), exercise)
end
end
end

View File

@ -16,14 +16,12 @@ describe ExternalUserPolicy do
end
end
[:index?].each do |action|
permissions(action) do
it 'grants access to admins and teachers only' do
expect(policy).to permit(build(:admin), ExternalUser.new)
expect(policy).to permit(build(:teacher), ExternalUser.new)
[:external_user].each do |factory_name|
expect(policy).not_to permit(build(factory_name), ExternalUser.new)
end
permissions :index? do
it 'grants access to admins and teachers only' do
expect(policy).to permit(build(:admin), ExternalUser.new)
expect(policy).to permit(build(:teacher), ExternalUser.new)
[:external_user].each do |factory_name|
expect(policy).not_to permit(build(factory_name), ExternalUser.new)
end
end
end

467
yarn.lock
View File

@ -17,38 +17,38 @@
dependencies:
"@babel/highlight" "^7.18.6"
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8":
version "7.18.8"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.0.tgz#2a592fd89bacb1fcde68de31bee4f2f2dacb0e86"
integrity sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==
"@babel/core@^7.18.10":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8"
integrity sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==
"@babel/core@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.0.tgz#d2f5f4f2033c00de8096be3c9f45772563e150c3"
integrity sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==
dependencies:
"@ampproject/remapping" "^2.1.0"
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.18.10"
"@babel/helper-compilation-targets" "^7.18.9"
"@babel/helper-module-transforms" "^7.18.9"
"@babel/helpers" "^7.18.9"
"@babel/parser" "^7.18.10"
"@babel/generator" "^7.19.0"
"@babel/helper-compilation-targets" "^7.19.0"
"@babel/helper-module-transforms" "^7.19.0"
"@babel/helpers" "^7.19.0"
"@babel/parser" "^7.19.0"
"@babel/template" "^7.18.10"
"@babel/traverse" "^7.18.10"
"@babel/types" "^7.18.10"
"@babel/traverse" "^7.19.0"
"@babel/types" "^7.19.0"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.1"
semver "^6.3.0"
"@babel/generator@^7.18.10":
version "7.18.12"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.12.tgz#fa58daa303757bd6f5e4bbca91b342040463d9f4"
integrity sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==
"@babel/generator@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.0.tgz#785596c06425e59334df2ccee63ab166b738419a"
integrity sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==
dependencies:
"@babel/types" "^7.18.10"
"@babel/types" "^7.19.0"
"@jridgewell/gen-mapping" "^0.3.2"
jsesc "^2.5.1"
@ -67,33 +67,33 @@
"@babel/helper-explode-assignable-expression" "^7.18.6"
"@babel/types" "^7.18.9"
"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf"
integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz#537ec8339d53e806ed422f1e06c8f17d55b96bb0"
integrity sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==
dependencies:
"@babel/compat-data" "^7.18.8"
"@babel/compat-data" "^7.19.0"
"@babel/helper-validator-option" "^7.18.6"
browserslist "^4.20.2"
semver "^6.3.0"
"@babel/helper-create-class-features-plugin@^7.18.6":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz#d802ee16a64a9e824fcbf0a2ffc92f19d58550ce"
integrity sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz#bfd6904620df4e46470bae4850d66be1054c404b"
integrity sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.18.9"
"@babel/helper-function-name" "^7.19.0"
"@babel/helper-member-expression-to-functions" "^7.18.9"
"@babel/helper-optimise-call-expression" "^7.18.6"
"@babel/helper-replace-supers" "^7.18.9"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/helper-create-regexp-features-plugin@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz#3e35f4e04acbbf25f1b3534a657610a000543d3c"
integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz#7976aca61c0984202baca73d84e2337a5424a41b"
integrity sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
regexpu-core "^5.1.0"
@ -122,13 +122,13 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-function-name@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0"
integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==
"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c"
integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==
dependencies:
"@babel/template" "^7.18.6"
"@babel/types" "^7.18.9"
"@babel/template" "^7.18.10"
"@babel/types" "^7.19.0"
"@babel/helper-hoist-variables@^7.18.6":
version "7.18.6"
@ -151,19 +151,19 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712"
integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==
"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz#309b230f04e22c58c6a2c0c0c7e50b216d350c30"
integrity sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==
dependencies:
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-module-imports" "^7.18.6"
"@babel/helper-simple-access" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/helper-validator-identifier" "^7.18.6"
"@babel/template" "^7.18.6"
"@babel/traverse" "^7.18.9"
"@babel/types" "^7.18.9"
"@babel/template" "^7.18.10"
"@babel/traverse" "^7.19.0"
"@babel/types" "^7.19.0"
"@babel/helper-optimise-call-expression@^7.18.6":
version "7.18.6"
@ -172,10 +172,10 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f"
integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf"
integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==
"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9":
version "7.18.9"
@ -235,23 +235,23 @@
integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
"@babel/helper-wrap-function@^7.18.9":
version "7.18.11"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz#bff23ace436e3f6aefb61f85ffae2291c80ed1fb"
integrity sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz#89f18335cff1152373222f76a4b37799636ae8b1"
integrity sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==
dependencies:
"@babel/helper-function-name" "^7.18.9"
"@babel/helper-function-name" "^7.19.0"
"@babel/template" "^7.18.10"
"@babel/traverse" "^7.18.11"
"@babel/types" "^7.18.10"
"@babel/traverse" "^7.19.0"
"@babel/types" "^7.19.0"
"@babel/helpers@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9"
integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==
"@babel/helpers@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.0.tgz#f30534657faf246ae96551d88dd31e9d1fa1fc18"
integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==
dependencies:
"@babel/template" "^7.18.6"
"@babel/traverse" "^7.18.9"
"@babel/types" "^7.18.9"
"@babel/template" "^7.18.10"
"@babel/traverse" "^7.19.0"
"@babel/types" "^7.19.0"
"@babel/highlight@^7.18.6":
version "7.18.6"
@ -262,10 +262,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.18.10", "@babel/parser@^7.18.11":
version "7.18.11"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9"
integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==
"@babel/parser@^7.18.10", "@babel/parser@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.0.tgz#497fcafb1d5b61376959c1c338745ef0577aa02c"
integrity sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
version "7.18.6"
@ -283,13 +283,13 @@
"@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
"@babel/plugin-proposal-optional-chaining" "^7.18.9"
"@babel/plugin-proposal-async-generator-functions@^7.18.10":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz#85ea478c98b0095c3e4102bff3b67d306ed24952"
integrity sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==
"@babel/plugin-proposal-async-generator-functions@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.0.tgz#cf5740194f170467df20581712400487efc79ff1"
integrity sha512-nhEByMUTx3uZueJ/QkJuSlCfN4FGg+xy+vRsfGQGzSauq5ks2Deid2+05Q3KhfaUjvec1IGhw/Zm3cFm8JigTQ==
dependencies:
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-plugin-utils" "^7.18.9"
"@babel/helper-plugin-utils" "^7.19.0"
"@babel/helper-remap-async-to-generator" "^7.18.9"
"@babel/plugin-syntax-async-generators" "^7.8.4"
@ -547,16 +547,17 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
"@babel/plugin-transform-classes@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz#90818efc5b9746879b869d5ce83eb2aa48bbc3da"
integrity sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==
"@babel/plugin-transform-classes@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz#0e61ec257fba409c41372175e7c1e606dc79bb20"
integrity sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
"@babel/helper-compilation-targets" "^7.19.0"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.18.9"
"@babel/helper-function-name" "^7.19.0"
"@babel/helper-optimise-call-expression" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.9"
"@babel/helper-plugin-utils" "^7.19.0"
"@babel/helper-replace-supers" "^7.18.9"
"@babel/helper-split-export-declaration" "^7.18.6"
globals "^11.1.0"
@ -568,10 +569,10 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
"@babel/plugin-transform-destructuring@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz#68906549c021cb231bee1db21d3b5b095f8ee292"
integrity sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA==
"@babel/plugin-transform-destructuring@^7.18.13":
version "7.18.13"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz#9e03bc4a94475d62b7f4114938e6c5c33372cbf5"
integrity sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow==
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
@ -647,14 +648,14 @@
"@babel/helper-simple-access" "^7.18.6"
babel-plugin-dynamic-import-node "^2.3.3"
"@babel/plugin-transform-modules-systemjs@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz#545df284a7ac6a05125e3e405e536c5853099a06"
integrity sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==
"@babel/plugin-transform-modules-systemjs@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz#5f20b471284430f02d9c5059d9b9a16d4b085a1f"
integrity sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==
dependencies:
"@babel/helper-hoist-variables" "^7.18.6"
"@babel/helper-module-transforms" "^7.18.9"
"@babel/helper-plugin-utils" "^7.18.9"
"@babel/helper-module-transforms" "^7.19.0"
"@babel/helper-plugin-utils" "^7.19.0"
"@babel/helper-validator-identifier" "^7.18.6"
babel-plugin-dynamic-import-node "^2.3.3"
@ -666,13 +667,13 @@
"@babel/helper-module-transforms" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-named-capturing-groups-regex@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d"
integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==
"@babel/plugin-transform-named-capturing-groups-regex@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.0.tgz#58c52422e4f91a381727faed7d513c89d7f41ada"
integrity sha512-HDSuqOQzkU//kfGdiHBt71/hkDTApw4U/cMVgKgX7PqfB3LOaK+2GtCEsBu1dL9CkswDm0Gwehht1dCr421ULQ==
dependencies:
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/helper-create-regexp-features-plugin" "^7.19.0"
"@babel/helper-plugin-utils" "^7.19.0"
"@babel/plugin-transform-new-target@^7.18.6":
version "7.18.6"
@ -737,12 +738,12 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-spread@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz#6ea7a6297740f381c540ac56caf75b05b74fb664"
integrity sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==
"@babel/plugin-transform-spread@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz#dd60b4620c2fec806d60cfaae364ec2188d593b6"
integrity sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
"@babel/helper-plugin-utils" "^7.19.0"
"@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
"@babel/plugin-transform-sticky-regex@^7.18.6":
@ -782,17 +783,17 @@
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/preset-env@7":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.10.tgz#83b8dfe70d7eea1aae5a10635ab0a5fe60dfc0f4"
integrity sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.19.0.tgz#fd18caf499a67d6411b9ded68dc70d01ed1e5da7"
integrity sha512-1YUju1TAFuzjIQqNM9WsF4U6VbD/8t3wEAlw3LFYuuEr+ywqLRcSXxFKz4DCEj+sN94l/XTDiUXYRrsvMpz9WQ==
dependencies:
"@babel/compat-data" "^7.18.8"
"@babel/helper-compilation-targets" "^7.18.9"
"@babel/helper-plugin-utils" "^7.18.9"
"@babel/compat-data" "^7.19.0"
"@babel/helper-compilation-targets" "^7.19.0"
"@babel/helper-plugin-utils" "^7.19.0"
"@babel/helper-validator-option" "^7.18.6"
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6"
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9"
"@babel/plugin-proposal-async-generator-functions" "^7.18.10"
"@babel/plugin-proposal-async-generator-functions" "^7.19.0"
"@babel/plugin-proposal-class-properties" "^7.18.6"
"@babel/plugin-proposal-class-static-block" "^7.18.6"
"@babel/plugin-proposal-dynamic-import" "^7.18.6"
@ -826,9 +827,9 @@
"@babel/plugin-transform-async-to-generator" "^7.18.6"
"@babel/plugin-transform-block-scoped-functions" "^7.18.6"
"@babel/plugin-transform-block-scoping" "^7.18.9"
"@babel/plugin-transform-classes" "^7.18.9"
"@babel/plugin-transform-classes" "^7.19.0"
"@babel/plugin-transform-computed-properties" "^7.18.9"
"@babel/plugin-transform-destructuring" "^7.18.9"
"@babel/plugin-transform-destructuring" "^7.18.13"
"@babel/plugin-transform-dotall-regex" "^7.18.6"
"@babel/plugin-transform-duplicate-keys" "^7.18.9"
"@babel/plugin-transform-exponentiation-operator" "^7.18.6"
@ -838,9 +839,9 @@
"@babel/plugin-transform-member-expression-literals" "^7.18.6"
"@babel/plugin-transform-modules-amd" "^7.18.6"
"@babel/plugin-transform-modules-commonjs" "^7.18.6"
"@babel/plugin-transform-modules-systemjs" "^7.18.9"
"@babel/plugin-transform-modules-systemjs" "^7.19.0"
"@babel/plugin-transform-modules-umd" "^7.18.6"
"@babel/plugin-transform-named-capturing-groups-regex" "^7.18.6"
"@babel/plugin-transform-named-capturing-groups-regex" "^7.19.0"
"@babel/plugin-transform-new-target" "^7.18.6"
"@babel/plugin-transform-object-super" "^7.18.6"
"@babel/plugin-transform-parameters" "^7.18.8"
@ -848,14 +849,14 @@
"@babel/plugin-transform-regenerator" "^7.18.6"
"@babel/plugin-transform-reserved-words" "^7.18.6"
"@babel/plugin-transform-shorthand-properties" "^7.18.6"
"@babel/plugin-transform-spread" "^7.18.9"
"@babel/plugin-transform-spread" "^7.19.0"
"@babel/plugin-transform-sticky-regex" "^7.18.6"
"@babel/plugin-transform-template-literals" "^7.18.9"
"@babel/plugin-transform-typeof-symbol" "^7.18.9"
"@babel/plugin-transform-unicode-escapes" "^7.18.10"
"@babel/plugin-transform-unicode-regex" "^7.18.6"
"@babel/preset-modules" "^0.1.5"
"@babel/types" "^7.18.10"
"@babel/types" "^7.19.0"
babel-plugin-polyfill-corejs2 "^0.3.2"
babel-plugin-polyfill-corejs3 "^0.5.3"
babel-plugin-polyfill-regenerator "^0.4.0"
@ -874,13 +875,13 @@
esutils "^2.0.2"
"@babel/runtime@7", "@babel/runtime@^7.8.4":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.18.10", "@babel/template@^7.18.6":
"@babel/template@^7.18.10":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
@ -889,26 +890,26 @@
"@babel/parser" "^7.18.10"
"@babel/types" "^7.18.10"
"@babel/traverse@^7.18.10", "@babel/traverse@^7.18.11", "@babel/traverse@^7.18.9":
version "7.18.11"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.11.tgz#3d51f2afbd83ecf9912bcbb5c4d94e3d2ddaa16f"
integrity sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==
"@babel/traverse@^7.18.9", "@babel/traverse@^7.19.0":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.0.tgz#eb9c561c7360005c592cc645abafe0c3c4548eed"
integrity sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.18.10"
"@babel/generator" "^7.19.0"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.18.9"
"@babel/helper-function-name" "^7.19.0"
"@babel/helper-hoist-variables" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/parser" "^7.18.11"
"@babel/types" "^7.18.10"
"@babel/parser" "^7.19.0"
"@babel/types" "^7.19.0"
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.4.4":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6"
integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==
"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.4.4":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600"
integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==
dependencies:
"@babel/helper-string-parser" "^7.18.10"
"@babel/helper-validator-identifier" "^7.18.6"
@ -926,10 +927,10 @@
dependencies:
"@types/hammerjs" "^2.0.36"
"@fortawesome/fontawesome-free@^6.1.2":
version "6.1.2"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.2.tgz#d18880eddeadd42b1c64cb559f2f3d13d47a4a64"
integrity sha512-XwWADtfdSN73/udaFm+1mnGIj/ShDZNFMe/PRoqv3FhQ4GNI2PUN70yFTPsjq65Lw2C9i4TG5/hTbxXIXVCiqQ==
"@fortawesome/fontawesome-free@^6.2.0":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.0.tgz#ba3510825b332816fe7190f28827f8cb33a298b5"
integrity sha512-CNR7qRIfCwWHNN7FnKUniva94edPdyQzil/zCwk3v6k4R6rR2Fr8i4s3PM7n/lyfPA6Zfko9z5WDzFxG9SW1uQ==
"@jridgewell/gen-mapping@^0.1.0":
version "0.1.1"
@ -989,56 +990,46 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
"@sentry/browser@^6.11.0":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.7.tgz#a40b6b72d911b5f1ed70ed3b4e7d4d4e625c0b5f"
integrity sha512-oDbklp4O3MtAM4mtuwyZLrgO1qDVYIujzNJQzXmi9YzymJCuzMLSRDvhY83NNDCRxf0pds4DShgYeZdbSyKraA==
"@sentry/browser@^7.11.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.12.1.tgz#2be6fa5c2529a2a75abac4d00aca786362302a1a"
integrity sha512-pgyL65CrGFLe8sKcEG8KXAuVTE8zkAsyTlv/AuME06cSdxzO/memPK/r3BI6EM7WupIdga+V5tQUldeT1kgHNA==
dependencies:
"@sentry/core" "6.19.7"
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
"@sentry/core" "7.12.1"
"@sentry/types" "7.12.1"
"@sentry/utils" "7.12.1"
tslib "^1.9.3"
"@sentry/core@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785"
integrity sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==
"@sentry/core@7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.12.1.tgz#a22f1c530ed528a699ed204c36eb5fc8d308103d"
integrity sha512-DFHbzHFjukhlkRZ5xzfebx0IBzblW43kmfnalBBq7xEMscUvnhsYnlvL9Y20tuPZ/PrTcq4JAHbFluAvw6M0QQ==
dependencies:
"@sentry/hub" "6.19.7"
"@sentry/minimal" "6.19.7"
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
"@sentry/hub" "7.12.1"
"@sentry/types" "7.12.1"
"@sentry/utils" "7.12.1"
tslib "^1.9.3"
"@sentry/hub@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11"
integrity sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==
"@sentry/hub@7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.12.1.tgz#dffad40cd2b8f44df2d5f20a89df87879cbbf1c3"
integrity sha512-KLVnVqXf+CRmXNy9/T8K2/js7QvOQ94xtgP5KnWJbu2rl+JhxnIGiBRF51lPXFIatt7zWwB9qNdMS8lVsvLMGQ==
dependencies:
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
"@sentry/types" "7.12.1"
"@sentry/utils" "7.12.1"
tslib "^1.9.3"
"@sentry/minimal@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.7.tgz#b3ee46d6abef9ef3dd4837ebcb6bdfd01b9aa7b4"
integrity sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==
dependencies:
"@sentry/hub" "6.19.7"
"@sentry/types" "6.19.7"
tslib "^1.9.3"
"@sentry/types@7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.12.1.tgz#eff76d938f9effc62a2ec76cd5c3f04de37f5c15"
integrity sha512-VGZs39SZgMcCGv7H0VyFy1LEFGsnFZH590JUopmz6nG63EpeYQ2xzhIoPNAiLKbyUvBEwukn+faCg3u3MGqhgQ==
"@sentry/types@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7"
integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==
"@sentry/utils@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.7.tgz#6edd739f8185fd71afe49cbe351c1bbf5e7b7c79"
integrity sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==
"@sentry/utils@7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.12.1.tgz#fcf80fdc332d0bd288e21b13efc7a2f0d604f75a"
integrity sha512-Dh8B13pC0u8uLM/zf+oZngyg808c6BDEO94F7H+h3IciCVVd92A0cOQwLGAEdf8srnJgpZJNAlSC8lFDhbFHzQ==
dependencies:
"@sentry/types" "6.19.7"
"@sentry/types" "7.12.1"
tslib "^1.9.3"
"@trysound/sax@0.2.0":
@ -1085,9 +1076,9 @@
"@types/estree" "*"
"@types/eslint@*":
version "8.4.5"
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.5.tgz#acdfb7dd36b91cc5d812d7c093811a8f3d9b31e4"
integrity sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==
version "8.4.6"
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.6.tgz#7976f054c1bccfcf514bff0564c0c41df5c08207"
integrity sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==
dependencies:
"@types/estree" "*"
"@types/json-schema" "*"
@ -1144,9 +1135,9 @@
integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==
"@types/node@*":
version "18.7.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.6.tgz#31743bc5772b6ac223845e18c3fc26f042713c83"
integrity sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==
version "18.7.16"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.16.tgz#0eb3cce1e37c79619943d2fd903919fc30850601"
integrity sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==
"@types/qs@*":
version "6.9.7"
@ -1524,9 +1515,9 @@ body-parser@1.20.0:
unpipe "1.0.0"
bonjour-service@^1.0.11:
version "1.0.13"
resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.13.tgz#4ac003dc1626023252d58adf2946f57e5da450c1"
integrity sha512-LWKRU/7EqDUC9CTAQtuZl5HzBALoCYwtLhffW3et7vZMwv3bWLpJf8bRYlMD5OCcDpTfnPgNCV4yo9ZIaJGMiA==
version "1.0.14"
resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.14.tgz#c346f5bc84e87802d08f8d5a60b93f758e514ee7"
integrity sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==
dependencies:
array-flatten "^2.1.2"
dns-equal "^1.0.0"
@ -1538,10 +1529,10 @@ boolbase@^1.0.0:
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
bootstrap@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.0.tgz#838727fb60f1630db370fe57c63cbcf2962bb3d3"
integrity sha512-qlnS9GL6YZE6Wnef46GxGv1UpGGzAwO0aPL1yOjzDIJpeApeMvqV24iL+pjr2kU4dduoBA9fINKWKgMToobx9A==
bootstrap@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.1.tgz#45f97ff05cbe828bad807b014d8425f3aeb8ec3a"
integrity sha512-UQi3v2NpVPEi1n35dmRRzBJFlgvWHYwyem6yHhuT6afYF+sziEt46McRbT//kVXZ7b1YUYEVGdXEH74Nx3xzGA==
bootswatch@^5.2.0:
version "5.2.0"
@ -1607,9 +1598,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001370:
version "1.0.30001378"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001378.tgz#3d2159bf5a8f9ca093275b0d3ecc717b00f27b67"
integrity sha512-JVQnfoO7FK7WvU4ZkBRbPjaot4+YqxogSDosHv0Hv5mWpUESmN+UubMU6L/hGz8QlQ2aY5U0vR6MOs6j/CXpNA==
version "1.0.30001393"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001393.tgz#1aa161e24fe6af2e2ccda000fc2b94be0b0db356"
integrity sha512-N/od11RX+Gsk+1qY/jbPa0R6zJupEa0lxeBG598EbrtblxVCTJsQwbRBm6+V+rxpc5lHKdsXb9RY83cZIPLseA==
chalk@^2.0.0:
version "2.4.2"
@ -1784,12 +1775,11 @@ cookie@0.5.0:
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
core-js-compat@^3.21.0, core-js-compat@^3.22.1:
version "3.24.1"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.24.1.tgz#d1af84a17e18dfdd401ee39da9996f9a7ba887de"
integrity sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw==
version "3.25.1"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.1.tgz#6f13a90de52f89bbe6267e5620a412c7f7ff7e42"
integrity sha512-pOHS7O0i8Qt4zlPW/eIFjwp+NrTPx+wTL0ctgI2fHn31sZOq89rDsmtc/A2vAX7r6shl+bmVI+678He46jgBlw==
dependencies:
browserslist "^4.21.3"
semver "7.0.0"
core-util-is@~1.0.0:
version "1.0.3"
@ -1806,9 +1796,9 @@ cross-spawn@^7.0.3:
which "^2.0.1"
css-declaration-sorter@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.0.tgz#72ebd995c8f4532ff0036631f7365cce9759df14"
integrity sha512-OGT677UGHJTAVMRhPO+HJ4oKln3wkBTwtDFH0ojbqm+MJm6xuDMHp2nkhh/ThaBqq20IbraBQSWKfSLNHQO9Og==
version "6.3.1"
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec"
integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==
css-loader@^6.7.1:
version "6.7.1"
@ -2302,9 +2292,9 @@ ee-first@1.1.1:
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
electron-to-chromium@^1.4.202:
version "1.4.224"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.224.tgz#ecf2eed395cfedcbbe634658ccc4b457f7b254c3"
integrity sha512-dOujC5Yzj0nOVE23iD5HKqrRSDj2SD7RazpZS/b/WX85MtO6/LzKDF4TlYZTBteB+7fvSg5JpWh0sN7fImNF8w==
version "1.4.246"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.246.tgz#802132d1bbd3ff32ce82fcd6a6ed6ab59b4366dc"
integrity sha512-/wFCHUE+Hocqr/LlVGsuKLIw4P2lBWwFIDcNMDpJGzyIysQV4aycpoOitAs32FT94EHKnNqDR/CVZJFbXEufJA==
emojis-list@^3.0.0:
version "3.0.0"
@ -2708,10 +2698,10 @@ human-signals@^2.1.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
i18n-js@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/i18n-js/-/i18n-js-4.0.2.tgz#31a62520204e292675bd72e82abdfeeb9aed5f20"
integrity sha512-81geA9vPvWe4NI2uL8Ve+/2jM03Sj/IvGgFHPxij7DbSXbG3CfChRK1vBj2h2IRl6eVRZf3Eq4ug3PgeeWUUPA==
i18n-js@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/i18n-js/-/i18n-js-4.1.1.tgz#05ebd03c4d92f6dc26a00d7c5cfb90f9c326b67c"
integrity sha512-Uph8ghmfShexVhDcNtg5s40zprJZPrhW5iOEKsUwPiiBpIGN/0EJ9W7DTqhLFlWfAlpkFiaLxVxHsk8f+3KjIQ==
dependencies:
bignumber.js "*"
lodash "*"
@ -2882,10 +2872,10 @@ jquery-ujs@^1.2.3:
resolved "https://registry.yarnpkg.com/jquery-ujs/-/jquery-ujs-1.2.3.tgz#dcac6026ab7268e5ee41faf9d31c997cd4ddd603"
integrity sha512-59wvfx5vcCTHMeQT1/OwFiAj+UffLIwjRIoXdpO7Z7BCFGepzq9T9oLVeoItjTqjoXfUrHJvV7QU6pUR+UzOoA==
"jquery@>=1.8.0 <4.0.0", jquery@>=1.9.1, jquery@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470"
integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==
"jquery@>=1.8.0 <4.0.0", jquery@>=1.9.1, jquery@^3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.1.tgz#fab0408f8b45fc19f956205773b62b292c147a16"
integrity sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==
js-tokens@^4.0.0:
version "4.0.0"
@ -3830,10 +3820,10 @@ sass-loader@^13.0.2:
klona "^2.0.4"
neo-async "^2.6.2"
sass@^1.54.4:
version "1.54.4"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.4.tgz#803ff2fef5525f1dd01670c3915b4b68b6cba72d"
integrity sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==
sass@^1.54.9:
version "1.54.9"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.9.tgz#b05f14ed572869218d1a76961de60cd647221762"
integrity sha512-xb1hjASzEH+0L0WI9oFjqhRi51t/gagWnxLiwUNMltA0Ab6jIDkAacgKiGYKM9Jhy109osM7woEEai6SXeJo5Q==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
@ -3873,17 +3863,12 @@ select-hose@^2.0.0:
integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==
selfsigned@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.1.tgz#8b2df7fa56bf014d19b6007655fff209c0ef0a56"
integrity sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==
version "2.1.1"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61"
integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==
dependencies:
node-forge "^1"
semver@7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
@ -3955,10 +3940,10 @@ setprototypeof@1.2.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
shakapacker@6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-6.5.1.tgz#3c1554771c0498ea757cb86dfc06811875f4c2bd"
integrity sha512-yOVvek0fxAU3FUjWcT7GxpJ/zAbhKbGEw78HHYfMAHE95cDhxTAQjBwvChP/PlceiteXUryRI0Mrdy7jqXvmnw==
shakapacker@6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-6.5.2.tgz#dda95543107a71c7ada3f6ee102a1a31563c6738"
integrity sha512-32hpr/AuyQJEk/4J8quL/xLPl+NPR0mBvJ3D9AtwHIkbSTUA0++LZrvVO+aQ4S1Uy3Iz2KSI/JVRGGD/C4SFFg==
dependencies:
glob "^7.2.0"
js-yaml "^4.1.0"
@ -4148,10 +4133,10 @@ tapable@^2.0, tapable@^2.1.1, tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.5:
version "5.3.5"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.5.tgz#f7d82286031f915a4f8fb81af4bd35d2e3c011bc"
integrity sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==
terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.6:
version "5.3.6"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c"
integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==
dependencies:
"@jridgewell/trace-mapping" "^0.3.14"
jest-worker "^27.4.5"
@ -4160,9 +4145,9 @@ terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.5:
terser "^5.14.1"
terser@^5.14.1:
version "5.14.2"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
version "5.15.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.0.tgz#e16967894eeba6e1091509ec83f0c60e179f2425"
integrity sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==
dependencies:
"@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0"
@ -4209,6 +4194,11 @@ type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
typed-assert@^1.0.8:
version "1.0.9"
resolved "https://registry.yarnpkg.com/typed-assert/-/typed-assert-1.0.9.tgz#8af9d4f93432c4970ec717e3006f33f135b06213"
integrity sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==
underscore@^1.13.4:
version "1.13.4"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.4.tgz#7886b46bbdf07f768e0052f1828e1dcab40c0dee"
@ -4243,9 +4233,9 @@ unpipe@1.0.0, unpipe@~1.0.0:
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
update-browserslist-db@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38"
integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==
version "1.0.7"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz#16279639cff1d0f800b14792de43d97df2d11b7d"
integrity sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==
dependencies:
escalade "^3.1.1"
picocolors "^1.0.0"
@ -4349,10 +4339,10 @@ webpack-dev-middleware@^5.3.1:
range-parser "^1.2.1"
schema-utils "^4.0.0"
webpack-dev-server@^4.10.0:
version "4.10.0"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.10.0.tgz#de270d0009eba050546912be90116e7fd740a9ca"
integrity sha512-7dezwAs+k6yXVFZ+MaL8VnE+APobiO3zvpp3rBHe/HmWQ+avwh0Q3d0xxacOiBybZZ3syTZw9HXzpa3YNbAZDQ==
webpack-dev-server@^4.11.0:
version "4.11.0"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz#290ee594765cd8260adfe83b2d18115ea04484e7"
integrity sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==
dependencies:
"@types/bonjour" "^3.5.9"
"@types/connect-history-api-fallback" "^1.3.5"
@ -4397,6 +4387,13 @@ webpack-sources@^3.2.3:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack-subresource-integrity@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz#8b7606b033c6ccac14e684267cb7fb1f5c2a132a"
integrity sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==
dependencies:
typed-assert "^1.0.8"
webpack@^5.74.0:
version "5.74.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980"