Commit 6e2a8af2 authored by Stan Hu's avatar Stan Hu

Merge branch 'ce-to-ee-2018-02-13' into 'master'

CE upstream - 2018-02-13 03:23 UTC

See merge request gitlab-org/gitlab-ee!4498
parents 4683a0f2 bec22f8a
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import Vue from 'vue'; import Vue from 'vue';
import weight from 'ee/sidebar/components/weight/weight.vue'; import weight from 'ee/sidebar/components/weight/weight.vue';
import Flash from '../../flash'; import Flash from '../../flash';
import { __ } from '../../locale';
import Sidebar from '../../right_sidebar'; import Sidebar from '../../right_sidebar';
import eventHub from '../../sidebar/event_hub'; import eventHub from '../../sidebar/event_hub';
import assigneeTitle from '../../sidebar/components/assignees/assignee_title'; import assigneeTitle from '../../sidebar/components/assignees/assignee_title';
...@@ -96,7 +97,7 @@ gl.issueBoards.BoardSidebar = Vue.extend({ ...@@ -96,7 +97,7 @@ gl.issueBoards.BoardSidebar = Vue.extend({
}) })
.catch(() => { .catch(() => {
this.loadingAssignees = false; this.loadingAssignees = false;
return new Flash('An error occurred while saving assignees'); Flash(__('An error occurred while saving assignees'));
}); });
}, },
}, },
......
/* eslint-disable no-new */
import Vue from 'vue'; import Vue from 'vue';
import Flash from '../../../flash'; import Flash from '../../../flash';
import { __ } from '../../../locale';
import './lists_dropdown'; import './lists_dropdown';
import { pluralize } from '../../../lib/utils/text_utility'; import { pluralize } from '../../../lib/utils/text_utility';
...@@ -42,7 +41,7 @@ gl.issueBoards.ModalFooter = Vue.extend({ ...@@ -42,7 +41,7 @@ gl.issueBoards.ModalFooter = Vue.extend({
assignee_ids: assigneeIds, assignee_ids: assigneeIds,
weight: currentBoard.weight, weight: currentBoard.weight,
}).catch(() => { }).catch(() => {
new Flash('Failed to update issues, please try again.', 'alert'); Flash(__('Failed to update issues, please try again.'));
selectedIssues.forEach((issue) => { selectedIssues.forEach((issue) => {
list.removeIssue(issue); list.removeIssue(issue);
......
/* eslint-disable no-new */
import Vue from 'vue'; import Vue from 'vue';
import Flash from '../../../flash'; import Flash from '../../../flash';
import { __ } from '../../../locale';
const Store = gl.issueBoards.BoardsStore; const Store = gl.issueBoards.BoardsStore;
...@@ -69,7 +68,7 @@ gl.issueBoards.RemoveIssueBtn = Vue.extend({ ...@@ -69,7 +68,7 @@ gl.issueBoards.RemoveIssueBtn = Vue.extend({
// Post the remove data // Post the remove data
Vue.http.patch(this.updateUrl, data).catch(() => { Vue.http.patch(this.updateUrl, data).catch(() => {
new Flash('Failed to remove issue from board, please try again.', 'alert'); Flash(__('Failed to remove issue from board, please try again.'));
lists.forEach((list) => { lists.forEach((list) => {
list.addIssue(issue); list.addIssue(issue);
......
/* global katex */ import { __ } from './locale';
import flash from './flash';
// Renders math using KaTeX in any element with the // Renders math using KaTeX in any element with the
// `js-render-math` class // `js-render-math` class
...@@ -8,15 +9,8 @@ ...@@ -8,15 +9,8 @@
// <code class="js-render-math"></div> // <code class="js-render-math"></div>
// //
import { __ } from './locale';
import axios from './lib/utils/axios_utils';
import flash from './flash';
// Only load once
let katexLoaded = false;
// Loop over all math elements and render math // Loop over all math elements and render math
function renderWithKaTeX(elements) { function renderWithKaTeX(elements, katex) {
elements.each(function katexElementsLoop() { elements.each(function katexElementsLoop() {
const mathNode = $('<span></span>'); const mathNode = $('<span></span>');
const $this = $(this); const $this = $(this);
...@@ -34,30 +28,10 @@ function renderWithKaTeX(elements) { ...@@ -34,30 +28,10 @@ function renderWithKaTeX(elements) {
export default function renderMath($els) { export default function renderMath($els) {
if (!$els.length) return; if (!$els.length) return;
Promise.all([
if (katexLoaded) { import(/* webpackChunkName: 'katex' */ 'katex'),
renderWithKaTeX($els); import(/* webpackChunkName: 'katex' */ 'katex/dist/katex.css'),
} else { ]).then(([katex]) => {
axios.get(gon.katex_css_url) renderWithKaTeX($els, katex);
.then(() => { }).catch(() => flash(__('An error occurred while rendering KaTeX')));
const css = $('<link>', {
rel: 'stylesheet',
type: 'text/css',
href: gon.katex_css_url,
});
css.appendTo('head');
})
.then(() => axios.get(gon.katex_js_url, {
responseType: 'text',
}))
.then(({ data }) => {
// Add katex js to our document
$.globalEval(data);
})
.then(() => {
katexLoaded = true;
renderWithKaTeX($els); // Run KaTeX
})
.catch(() => flash(__('An error occurred while rendering KaTeX')));
}
} }
...@@ -36,8 +36,9 @@ class Key < ActiveRecord::Base ...@@ -36,8 +36,9 @@ class Key < ActiveRecord::Base
after_destroy :refresh_user_cache after_destroy :refresh_user_cache
def key=(value) def key=(value)
write_attribute(:key, value.present? ? Gitlab::SSHPublicKey.sanitize(value) : nil) value&.delete!("\n\r")
value.strip! unless value.blank?
write_attribute(:key, value)
@public_key = nil @public_key = nil
end end
...@@ -99,7 +100,7 @@ class Key < ActiveRecord::Base ...@@ -99,7 +100,7 @@ class Key < ActiveRecord::Base
def generate_fingerprint def generate_fingerprint
self.fingerprint = nil self.fingerprint = nil
return unless public_key.valid? return unless self.key.present?
self.fingerprint = public_key.fingerprint self.fingerprint = public_key.fingerprint
end end
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
Edit Edit
- if @project.group - if @project.group
= link_to promote_project_milestone_path(@milestone.project, @milestone), title: "Promote to Group Milestone", class: 'btn btn-grouped', data: { confirm: "You are about to promote #{@milestone.title} to a group level. This will make this milestone available to all projects inside #{@project.group.name}. The existing project milestone will be merged into the group level. This action cannot be reversed.", toggle: "tooltip" }, method: :post do = link_to promote_project_milestone_path(@milestone.project, @milestone), title: "Promote to Group Milestone", class: 'btn btn-grouped', data: { confirm: "Promoting #{@milestone.title} will make it available for all projects inside #{@project.group.name}. Existing project milestones with the same name will be merged. This action cannot be reversed.", toggle: "tooltip" }, method: :post do
Promote Promote
- if @milestone.active? - if @milestone.active?
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
.pull-right.hidden-xs.hidden-sm .pull-right.hidden-xs.hidden-sm
- if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group) - if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group)
= link_to promote_project_label_path(label.project, label), title: "Promote to Group Label", class: 'btn btn-transparent btn-action', data: {confirm: "You are about to promote #{label.title} to a group level. This will make this milestone available to all projects inside #{label.project.group.name}. The existing project label will be merged into the group level. This action cannot be reversed.", toggle: "tooltip"}, method: :post do = link_to promote_project_label_path(label.project, label), title: "Promote to Group Label", class: 'btn btn-transparent btn-action', data: {confirm: "Promoting #{label.title} will make it available for all projects inside #{label.project.group.name}. Existing project labels with the same name will be merged. This action cannot be reversed.", toggle: "tooltip"}, method: :post do
%span.sr-only Promote to Group %span.sr-only Promote to Group
= sprite_icon('level-up') = sprite_icon('level-up')
- if can?(current_user, :admin_label, label) - if can?(current_user, :admin_label, label)
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
\ \
- if @project.group - if @project.group
= link_to promote_project_milestone_path(milestone.project, milestone), title: "Promote to Group Milestone", class: 'btn btn-xs btn-grouped', data: { confirm: "You are about to promote #{milestone.title} to a group level. This will make this milestone available to all projects inside #{@project.group.name}. The existing project milestone will be merged into the group level. This action cannot be reversed.", toggle: "tooltip" }, method: :post do = link_to promote_project_milestone_path(milestone.project, milestone), title: "Promote to Group Milestone", class: 'btn btn-xs btn-grouped', data: { confirm: "Promoting #{milestone.title} will make it available for all projects inside #{@project.group.name}. Existing project milestones with the same name will be merged. This action cannot be reversed.", toggle: "tooltip" }, method: :post do
Promote Promote
= link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close btn-grouped" = link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close btn-grouped"
......
---
title: Sanitize extra blank spaces used when uploading a SSH key
merge_request: 40552
author:
type: fixed
---
title: Updated the katex library
merge_request: 15864
author:
type: other
...@@ -122,8 +122,6 @@ module Gitlab ...@@ -122,8 +122,6 @@ module Gitlab
config.assets.precompile << "print.css" config.assets.precompile << "print.css"
config.assets.precompile << "notify.css" config.assets.precompile << "notify.css"
config.assets.precompile << "mailers/*.css" config.assets.precompile << "mailers/*.css"
config.assets.precompile << "katex.css"
config.assets.precompile << "katex.js"
config.assets.precompile << "xterm/xterm.css" config.assets.precompile << "xterm/xterm.css"
config.assets.precompile << "performance_bar.css" config.assets.precompile << "performance_bar.css"
config.assets.precompile << "lib/ace.js" config.assets.precompile << "lib/ace.js"
......
...@@ -168,6 +168,27 @@ var config = { ...@@ -168,6 +168,27 @@ var config = {
name: '[name].[hash].[ext]', name: '[name].[hash].[ext]',
} }
}, },
{
test: /katex.css$/,
include: /node_modules\/katex\/dist/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
name: '[name].[hash].[ext]'
}
},
],
},
{
test: /\.(eot|ttf|woff|woff2)$/,
include: /node_modules\/katex\/dist\/fonts/,
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
}
},
{ {
test: /monaco-editor\/\w+\/vs\/loader\.js$/, test: /monaco-editor\/\w+\/vs\/loader\.js$/,
use: [ use: [
......
...@@ -13,8 +13,6 @@ module Gitlab ...@@ -13,8 +13,6 @@ module Gitlab
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
gon.shortcuts_path = help_page_path('shortcuts') gon.shortcuts_path = help_page_path('shortcuts')
gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
gon.katex_css_url = ActionController::Base.helpers.asset_path('katex.css')
gon.katex_js_url = ActionController::Base.helpers.asset_path('katex.js')
gon.sentry_dsn = Gitlab::CurrentSettings.clientside_sentry_dsn if Gitlab::CurrentSettings.clientside_sentry_enabled gon.sentry_dsn = Gitlab::CurrentSettings.clientside_sentry_dsn if Gitlab::CurrentSettings.clientside_sentry_enabled
gon.gitlab_url = Gitlab.config.gitlab.url gon.gitlab_url = Gitlab.config.gitlab.url
gon.revision = Gitlab::REVISION gon.revision = Gitlab::REVISION
......
...@@ -42,7 +42,7 @@ module Gitlab ...@@ -42,7 +42,7 @@ module Gitlab
key, value = parsed_field.first key, value = parsed_field.first
if value.nil? if value.nil?
value = open_file(tmp_path) value = open_file(tmp_path, @request.params["#{key}.name"])
@open_files << value @open_files << value
else else
value = decorate_params_value(value, @request.params[key], tmp_path) value = decorate_params_value(value, @request.params[key], tmp_path)
...@@ -70,7 +70,7 @@ module Gitlab ...@@ -70,7 +70,7 @@ module Gitlab
case path_value case path_value
when nil when nil
value_hash[path_key] = open_file(tmp_path) value_hash[path_key] = open_file(tmp_path, value_hash.dig(path_key, '.name'))
@open_files << value_hash[path_key] @open_files << value_hash[path_key]
value_hash value_hash
when Hash when Hash
...@@ -81,8 +81,8 @@ module Gitlab ...@@ -81,8 +81,8 @@ module Gitlab
end end
end end
def open_file(path) def open_file(path, name)
::UploadedFile.new(path, File.basename(path), 'application/octet-stream') ::UploadedFile.new(path, name || File.basename(path), 'application/octet-stream')
end end
end end
......
...@@ -6,7 +6,7 @@ module Gitlab ...@@ -6,7 +6,7 @@ module Gitlab
# This ensures we don't produce any errors that users can't do anything # This ensures we don't produce any errors that users can't do anything
# about themselves. # about themselves.
def self.enable? def self.enable?
Gitlab.com? || Rails.env.development? || Rails.env.test? Rails.env.development? || Rails.env.test?
end end
# Allows the current request to execute any number of SQL queries. # Allows the current request to execute any number of SQL queries.
......
...@@ -21,22 +21,6 @@ module Gitlab ...@@ -21,22 +21,6 @@ module Gitlab
technology(name)&.supported_sizes technology(name)&.supported_sizes
end end
def self.sanitize(key_content)
ssh_type, *parts = key_content.strip.split
return key_content if parts.empty?
parts.each_with_object("#{ssh_type} ").with_index do |(part, content), index|
content << part
if Gitlab::SSHPublicKey.new(content).valid?
break [content, parts[index + 1]].compact.join(' ') # Add the comment part if present
elsif parts.size == index + 1 # return original content if we've reached the last element
break key_content
end
end
end
attr_reader :key_text, :key attr_reader :key_text, :key
# Unqualified MD5 fingerprint for compatibility # Unqualified MD5 fingerprint for compatibility
...@@ -53,23 +37,23 @@ module Gitlab ...@@ -53,23 +37,23 @@ module Gitlab
end end
def valid? def valid?
key.present? && bits && technology.supported_sizes.include?(bits) key.present?
end end
def type def type
technology.name if key.present? technology.name if valid?
end end
def bits def bits
return if key.blank? return unless valid?
case type case type
when :rsa when :rsa
key.n&.num_bits key.n.num_bits
when :dsa when :dsa
key.p&.num_bits key.p.num_bits
when :ecdsa when :ecdsa
key.group.order&.num_bits key.group.order.num_bits
when :ed25519 when :ed25519
256 256
else else
......
...@@ -5,10 +5,6 @@ FactoryBot.define do ...@@ -5,10 +5,6 @@ FactoryBot.define do
title title
key { Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate + ' dummy@gitlab.com' } key { Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate + ' dummy@gitlab.com' }
factory :key_without_comment do
key { Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate }
end
factory :deploy_key, class: 'DeployKey' factory :deploy_key, class: 'DeployKey'
factory :personal_key do factory :personal_key do
......
import Vue from 'vue'; import Vue from 'vue';
import MarkdownComponent from '~/notebook/cells/markdown.vue'; import MarkdownComponent from '~/notebook/cells/markdown.vue';
import katex from 'vendor/katex'; import katex from 'katex';
const Component = Vue.extend(MarkdownComponent); const Component = Vue.extend(MarkdownComponent);
......
...@@ -5,15 +5,17 @@ require 'tempfile' ...@@ -5,15 +5,17 @@ require 'tempfile'
describe Gitlab::Middleware::Multipart do describe Gitlab::Middleware::Multipart do
let(:app) { double(:app) } let(:app) { double(:app) }
let(:middleware) { described_class.new(app) } let(:middleware) { described_class.new(app) }
let(:original_filename) { 'filename' }
it 'opens top-level files' do it 'opens top-level files' do
Tempfile.open('top-level') do |tempfile| Tempfile.open('top-level') do |tempfile|
env = post_env({ 'file' => tempfile.path }, { 'file.name' => 'filename' }, Gitlab::Workhorse.secret, 'gitlab-workhorse') env = post_env({ 'file' => tempfile.path }, { 'file.name' => original_filename }, Gitlab::Workhorse.secret, 'gitlab-workhorse')
expect(app).to receive(:call) do |env| expect(app).to receive(:call) do |env|
file = Rack::Request.new(env).params['file'] file = Rack::Request.new(env).params['file']
expect(file).to be_a(::UploadedFile) expect(file).to be_a(::UploadedFile)
expect(file.path).to eq(tempfile.path) expect(file.path).to eq(tempfile.path)
expect(file.original_filename).to eq(original_filename)
end end
middleware.call(env) middleware.call(env)
...@@ -34,13 +36,14 @@ describe Gitlab::Middleware::Multipart do ...@@ -34,13 +36,14 @@ describe Gitlab::Middleware::Multipart do
it 'opens files one level deep' do it 'opens files one level deep' do
Tempfile.open('one-level') do |tempfile| Tempfile.open('one-level') do |tempfile|
in_params = { 'user' => { 'avatar' => { '.name' => 'filename' } } } in_params = { 'user' => { 'avatar' => { '.name' => original_filename } } }
env = post_env({ 'user[avatar]' => tempfile.path }, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse') env = post_env({ 'user[avatar]' => tempfile.path }, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse')
expect(app).to receive(:call) do |env| expect(app).to receive(:call) do |env|
file = Rack::Request.new(env).params['user']['avatar'] file = Rack::Request.new(env).params['user']['avatar']
expect(file).to be_a(::UploadedFile) expect(file).to be_a(::UploadedFile)
expect(file.path).to eq(tempfile.path) expect(file.path).to eq(tempfile.path)
expect(file.original_filename).to eq(original_filename)
end end
middleware.call(env) middleware.call(env)
...@@ -49,13 +52,14 @@ describe Gitlab::Middleware::Multipart do ...@@ -49,13 +52,14 @@ describe Gitlab::Middleware::Multipart do
it 'opens files two levels deep' do it 'opens files two levels deep' do
Tempfile.open('two-levels') do |tempfile| Tempfile.open('two-levels') do |tempfile|
in_params = { 'project' => { 'milestone' => { 'themesong' => { '.name' => 'filename' } } } } in_params = { 'project' => { 'milestone' => { 'themesong' => { '.name' => original_filename } } } }
env = post_env({ 'project[milestone][themesong]' => tempfile.path }, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse') env = post_env({ 'project[milestone][themesong]' => tempfile.path }, in_params, Gitlab::Workhorse.secret, 'gitlab-workhorse')
expect(app).to receive(:call) do |env| expect(app).to receive(:call) do |env|
file = Rack::Request.new(env).params['project']['milestone']['themesong'] file = Rack::Request.new(env).params['project']['milestone']['themesong']
expect(file).to be_a(::UploadedFile) expect(file).to be_a(::UploadedFile)
expect(file.path).to eq(tempfile.path) expect(file.path).to eq(tempfile.path)
expect(file.original_filename).to eq(original_filename)
end end
middleware.call(env) middleware.call(env)
......
...@@ -12,14 +12,16 @@ describe Gitlab::QueryLimiting do ...@@ -12,14 +12,16 @@ describe Gitlab::QueryLimiting do
expect(described_class.enable?).to eq(true) expect(described_class.enable?).to eq(true)
end end
it 'returns true on GitLab.com' do it 'returns false on GitLab.com' do
expect(Rails.env).to receive(:development?).and_return(false)
expect(Rails.env).to receive(:test?).and_return(false)
allow(Gitlab).to receive(:com?).and_return(true) allow(Gitlab).to receive(:com?).and_return(true)
expect(described_class.enable?).to eq(true) expect(described_class.enable?).to eq(false)
end end
it 'returns true in a non GitLab.com' do it 'returns false in a non GitLab.com' do
expect(Gitlab).to receive(:com?).and_return(false) allow(Gitlab).to receive(:com?).and_return(false)
expect(Rails.env).to receive(:development?).and_return(false) expect(Rails.env).to receive(:development?).and_return(false)
expect(Rails.env).to receive(:test?).and_return(false) expect(Rails.env).to receive(:test?).and_return(false)
......
...@@ -37,41 +37,6 @@ describe Gitlab::SSHPublicKey, lib: true do ...@@ -37,41 +37,6 @@ describe Gitlab::SSHPublicKey, lib: true do
end end
end end
describe '.sanitize(key_content)' do
let(:content) { build(:key).key }
context 'when key has blank space characters' do
it 'removes the extra blank space characters' do
unsanitized = content.insert(100, "\n")
.insert(40, "\r\n")
.insert(30, ' ')
sanitized = described_class.sanitize(unsanitized)
_, body = sanitized.split
expect(sanitized).not_to eq(unsanitized)
expect(body).not_to match(/\s/)
end
end
context "when key doesn't have blank space characters" do
it "doesn't modify the content" do
sanitized = described_class.sanitize(content)
expect(sanitized).to eq(content)
end
end
context "when key is invalid" do
it 'returns the original content' do
unsanitized = "ssh-foo any content=="
sanitized = described_class.sanitize(unsanitized)
expect(sanitized).to eq(unsanitized)
end
end
end
describe '#valid?' do describe '#valid?' do
subject { public_key } subject { public_key }
......
...@@ -72,52 +72,15 @@ describe Key, :mailer do ...@@ -72,52 +72,15 @@ describe Key, :mailer do
expect(build(:key)).to be_valid expect(build(:key)).to be_valid
end end
it 'rejects the unfingerprintable key (not a key)' do it 'accepts a key with newline charecters after stripping them' do
expect(build(:key, key: 'ssh-rsa an-invalid-key==')).not_to be_valid key = build(:key)
end key.key = key.key.insert(100, "\n")
key.key = key.key.insert(40, "\r\n")
where(:factory, :chars, :expected_sections) do expect(key).to be_valid
[
[:key, ["\n", "\r\n"], 3],
[:key, [' ', ' '], 3],
[:key_without_comment, [' ', ' '], 2]
]
end
with_them do
let!(:key) { create(factory) }
let!(:original_fingerprint) { key.fingerprint }
it 'accepts a key with blank space characters after stripping them' do
modified_key = key.key.insert(100, chars.first).insert(40, chars.last)
_, content = modified_key.split
key.update!(key: modified_key)
expect(key).to be_valid
expect(key.key.split.size).to eq(expected_sections)
expect(content).not_to match(/\s/)
expect(original_fingerprint).to eq(key.fingerprint)
end
end
end
context 'validate size' do
where(:key_content, :result) do
[
[Spec::Support::Helpers::KeyGeneratorHelper.new(512).generate, false],
[Spec::Support::Helpers::KeyGeneratorHelper.new(8192).generate, false],
[Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate, true]
]
end end
with_them do it 'rejects the unfingerprintable key (not a key)' do
it 'validates the size of the key' do expect(build(:key, key: 'ssh-rsa an-invalid-key==')).not_to be_valid
key = build(:key, key: key_content)
expect(key.valid?).to eq(result)
end
end end
end end
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment