Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master
commit
6290cd7969
1
.babelrc
1
.babelrc
|
@ -4,7 +4,6 @@
|
||||||
[
|
[
|
||||||
"env",
|
"env",
|
||||||
{
|
{
|
||||||
"debug": true,
|
|
||||||
"exclude": ["transform-async-to-generator", "transform-regenerator"],
|
"exclude": ["transform-async-to-generator", "transform-regenerator"],
|
||||||
"loose": true,
|
"loose": true,
|
||||||
"modules": false,
|
"modules": false,
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -73,7 +73,7 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
||||||
gem 'rqrcode', '~> 0.10'
|
gem 'rqrcode', '~> 0.10'
|
||||||
gem 'ruby-oembed', '~> 0.12', require: 'oembed'
|
gem 'ruby-oembed', '~> 0.12', require: 'oembed'
|
||||||
gem 'ruby-progressbar', '~> 1.4'
|
gem 'ruby-progressbar', '~> 1.4'
|
||||||
gem 'sanitize', '~> 4.4'
|
gem 'sanitize', '~> 4.6.4'
|
||||||
gem 'sidekiq', '~> 5.0'
|
gem 'sidekiq', '~> 5.0'
|
||||||
gem 'sidekiq-scheduler', '~> 2.1'
|
gem 'sidekiq-scheduler', '~> 2.1'
|
||||||
gem 'sidekiq-unique-jobs', '~> 5.0'
|
gem 'sidekiq-unique-jobs', '~> 5.0'
|
||||||
|
|
12
Gemfile.lock
12
Gemfile.lock
|
@ -290,7 +290,7 @@ GEM
|
||||||
activesupport (>= 4, < 5.2)
|
activesupport (>= 4, < 5.2)
|
||||||
railties (>= 4, < 5.2)
|
railties (>= 4, < 5.2)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.1.1)
|
loofah (2.2.1)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.0)
|
mail (2.7.0)
|
||||||
|
@ -318,9 +318,9 @@ GEM
|
||||||
net-ssh (>= 2.6.5)
|
net-ssh (>= 2.6.5)
|
||||||
net-ssh (4.2.0)
|
net-ssh (4.2.0)
|
||||||
nio4r (2.1.0)
|
nio4r (2.1.0)
|
||||||
nokogiri (1.8.1)
|
nokogiri (1.8.2)
|
||||||
mini_portile2 (~> 2.3.0)
|
mini_portile2 (~> 2.3.0)
|
||||||
nokogumbo (1.4.13)
|
nokogumbo (1.5.0)
|
||||||
nokogiri
|
nokogiri
|
||||||
nsa (0.2.4)
|
nsa (0.2.4)
|
||||||
activesupport (>= 4.2, < 6)
|
activesupport (>= 4.2, < 6)
|
||||||
|
@ -499,10 +499,10 @@ GEM
|
||||||
rufus-scheduler (3.4.2)
|
rufus-scheduler (3.4.2)
|
||||||
et-orbi (~> 1.0)
|
et-orbi (~> 1.0)
|
||||||
safe_yaml (1.0.4)
|
safe_yaml (1.0.4)
|
||||||
sanitize (4.5.0)
|
sanitize (4.6.4)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.4.4)
|
nokogiri (>= 1.4.4)
|
||||||
nokogumbo (~> 1.4.1)
|
nokogumbo (~> 1.4)
|
||||||
sass (3.5.3)
|
sass (3.5.3)
|
||||||
sass-listen (~> 4.0.0)
|
sass-listen (~> 4.0.0)
|
||||||
sass-listen (4.0.0)
|
sass-listen (4.0.0)
|
||||||
|
@ -704,7 +704,7 @@ DEPENDENCIES
|
||||||
rubocop
|
rubocop
|
||||||
ruby-oembed (~> 0.12)
|
ruby-oembed (~> 0.12)
|
||||||
ruby-progressbar (~> 1.4)
|
ruby-progressbar (~> 1.4)
|
||||||
sanitize (~> 4.4)
|
sanitize (~> 4.6.4)
|
||||||
scss_lint (~> 0.55)
|
scss_lint (~> 0.55)
|
||||||
sidekiq (~> 5.0)
|
sidekiq (~> 5.0)
|
||||||
sidekiq-bulk (~> 0.1.1)
|
sidekiq-bulk (~> 0.1.1)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
|
import { CancelToken } from 'axios';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
|
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
|
||||||
import { tagHistory } from '../settings';
|
import { tagHistory } from '../settings';
|
||||||
|
@ -11,6 +12,8 @@ import {
|
||||||
refreshPublicTimeline,
|
refreshPublicTimeline,
|
||||||
} from './timelines';
|
} from './timelines';
|
||||||
|
|
||||||
|
let cancelFetchComposeSuggestionsAccounts;
|
||||||
|
|
||||||
export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
|
export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
|
||||||
export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
|
export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
|
||||||
export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
||||||
|
@ -257,13 +260,22 @@ export function undoUploadCompose(media_id) {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function clearComposeSuggestions() {
|
export function clearComposeSuggestions() {
|
||||||
|
if (cancelFetchComposeSuggestionsAccounts) {
|
||||||
|
cancelFetchComposeSuggestionsAccounts();
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_SUGGESTIONS_CLEAR,
|
type: COMPOSE_SUGGESTIONS_CLEAR,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {
|
const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {
|
||||||
|
if (cancelFetchComposeSuggestionsAccounts) {
|
||||||
|
cancelFetchComposeSuggestionsAccounts();
|
||||||
|
}
|
||||||
api(getState).get('/api/v1/accounts/search', {
|
api(getState).get('/api/v1/accounts/search', {
|
||||||
|
cancelToken: new CancelToken(cancel => {
|
||||||
|
cancelFetchComposeSuggestionsAccounts = cancel;
|
||||||
|
}),
|
||||||
params: {
|
params: {
|
||||||
q: token.slice(1),
|
q: token.slice(1),
|
||||||
resolve: false,
|
resolve: false,
|
||||||
|
|
|
@ -94,9 +94,16 @@ class Request
|
||||||
class Socket < TCPSocket
|
class Socket < TCPSocket
|
||||||
class << self
|
class << self
|
||||||
def open(host, *args)
|
def open(host, *args)
|
||||||
address = IPSocket.getaddress(host)
|
outer_e = nil
|
||||||
raise Mastodon::HostValidationError if PrivateAddressCheck.private_address? IPAddr.new(address)
|
Addrinfo.foreach(host, nil, nil, :SOCK_STREAM) do |address|
|
||||||
super address, *args
|
begin
|
||||||
|
raise Mastodon::HostValidationError if PrivateAddressCheck.private_address? IPAddr.new(address.ip_address)
|
||||||
|
return super address.ip_address, *args
|
||||||
|
rescue => e
|
||||||
|
outer_e = e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
raise outer_e if outer_e
|
||||||
end
|
end
|
||||||
|
|
||||||
alias new open
|
alias new open
|
||||||
|
|
|
@ -47,7 +47,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class Account < ApplicationRecord
|
class Account < ApplicationRecord
|
||||||
MENTION_RE = /(?<=^|[^\/[:word:]])@(([a-z0-9_]+)(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i
|
USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.]+[a-z0-9_]+)?/i
|
||||||
|
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE}?)(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i
|
||||||
|
|
||||||
include AccountAvatar
|
include AccountAvatar
|
||||||
include AccountFinderConcern
|
include AccountFinderConcern
|
||||||
|
@ -70,7 +71,8 @@ class Account < ApplicationRecord
|
||||||
validates :username, uniqueness: { scope: :domain, case_sensitive: true }, if: -> { !local? && will_save_change_to_username? }
|
validates :username, uniqueness: { scope: :domain, case_sensitive: true }, if: -> { !local? && will_save_change_to_username? }
|
||||||
|
|
||||||
# Local user validations
|
# Local user validations
|
||||||
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, uniqueness: { scope: :domain, case_sensitive: false }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? }
|
validates :username, format: { with: /\A#{USERNAME_RE}\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? }
|
||||||
|
validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
||||||
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
||||||
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
|
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
|
||||||
validate :note_length_does_not_exceed_length_limit, if: -> { local? && will_save_change_to_note? }
|
validate :note_length_does_not_exceed_length_limit, if: -> { local? && will_save_change_to_note? }
|
||||||
|
|
|
@ -16,7 +16,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
|
|
||||||
RedisLock.acquire(lock_options) do |lock|
|
RedisLock.acquire(lock_options) do |lock|
|
||||||
if lock.acquired?
|
if lock.acquired?
|
||||||
@account = Account.find_by(uri: @uri)
|
@account = Account.find_remote(@username, @domain)
|
||||||
@old_public_key = @account&.public_key
|
@old_public_key = @account&.public_key
|
||||||
@old_protocol = @account&.protocol
|
@old_protocol = @account&.protocol
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class UniqueUsernameValidator < ActiveModel::Validator
|
||||||
|
def validate(account)
|
||||||
|
return if account.username.nil?
|
||||||
|
|
||||||
|
normalized_username = account.username.downcase.delete('.')
|
||||||
|
|
||||||
|
scope = Account.where(domain: nil, username: normalized_username)
|
||||||
|
scope = scope.where.not(id: account.id) if account.persisted?
|
||||||
|
|
||||||
|
account.errors.add(:username, :taken) if scope.exists?
|
||||||
|
end
|
||||||
|
end
|
|
@ -77,9 +77,7 @@ module Mastodon
|
||||||
]
|
]
|
||||||
|
|
||||||
config.i18n.default_locale = ENV['DEFAULT_LOCALE']&.to_sym
|
config.i18n.default_locale = ENV['DEFAULT_LOCALE']&.to_sym
|
||||||
if config.i18n.available_locales.include?(config.i18n.default_locale)
|
unless config.i18n.available_locales.include?(config.i18n.default_locale)
|
||||||
config.i18n.fallbacks = [:en]
|
|
||||||
else
|
|
||||||
config.i18n.default_locale = :en
|
config.i18n.default_locale = :en
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,8 @@ Rails.application.configure do
|
||||||
# config.action_mailer.raise_delivery_errors = false
|
# config.action_mailer.raise_delivery_errors = false
|
||||||
|
|
||||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||||
# the I18n.default_locale when a translation cannot be found).
|
# English when a translation cannot be found).
|
||||||
config.i18n.fallbacks = true
|
config.i18n.fallbacks = [:en]
|
||||||
|
|
||||||
# Send deprecation notices to registered listeners.
|
# Send deprecation notices to registered listeners.
|
||||||
config.active_support.deprecation = :notify
|
config.active_support.deprecation = :notify
|
||||||
|
|
|
@ -55,6 +55,8 @@ module Devise
|
||||||
@@ldap_bind_dn = nil
|
@@ldap_bind_dn = nil
|
||||||
mattr_accessor :ldap_password
|
mattr_accessor :ldap_password
|
||||||
@@ldap_password = nil
|
@@ldap_password = nil
|
||||||
|
mattr_accessor :ldap_tls_no_verify
|
||||||
|
@@ldap_tls_no_verify = false
|
||||||
|
|
||||||
class Strategies::PamAuthenticatable
|
class Strategies::PamAuthenticatable
|
||||||
def valid?
|
def valid?
|
||||||
|
@ -357,5 +359,6 @@ Devise.setup do |config|
|
||||||
config.ldap_bind_dn = ENV.fetch('LDAP_BIND_DN')
|
config.ldap_bind_dn = ENV.fetch('LDAP_BIND_DN')
|
||||||
config.ldap_password = ENV.fetch('LDAP_PASSWORD')
|
config.ldap_password = ENV.fetch('LDAP_PASSWORD')
|
||||||
config.ldap_uid = ENV.fetch('LDAP_UID', 'cn')
|
config.ldap_uid = ENV.fetch('LDAP_UID', 'cn')
|
||||||
|
config.ldap_tls_no_verify = ENV['LDAP_TLS_NO_VERIFY'] == 'true'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
if ENV['LDAP_ENABLED'] == 'true'
|
require 'net/ldap'
|
||||||
require 'net/ldap'
|
require 'devise/strategies/authenticatable'
|
||||||
require 'devise/strategies/authenticatable'
|
|
||||||
|
|
||||||
module Devise
|
module Devise
|
||||||
module Strategies
|
module Strategies
|
||||||
class LdapAuthenticatable < Authenticatable
|
class LdapAuthenticatable < Authenticatable
|
||||||
def authenticate!
|
def authenticate!
|
||||||
|
@ -15,7 +14,7 @@ if ENV['LDAP_ENABLED'] == 'true'
|
||||||
base: Devise.ldap_base,
|
base: Devise.ldap_base,
|
||||||
encryption: {
|
encryption: {
|
||||||
method: Devise.ldap_method,
|
method: Devise.ldap_method,
|
||||||
tls_options: OpenSSL::SSL::SSLContext::DEFAULT_PARAMS,
|
tls_options: tls_options,
|
||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
method: :simple,
|
method: :simple,
|
||||||
|
@ -41,9 +40,14 @@ if ENV['LDAP_ENABLED'] == 'true'
|
||||||
def password
|
def password
|
||||||
params[:user][:password]
|
params[:user][:password]
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Warden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)
|
def tls_options
|
||||||
|
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.tap do |options|
|
||||||
|
options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if Devise.ldap_tls_no_verify
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Warden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)
|
||||||
|
|
|
@ -21,7 +21,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags
|
def flags
|
||||||
'rc3'
|
'rc4'
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_a
|
def to_a
|
||||||
|
|
|
@ -48,6 +48,13 @@ describe Request do
|
||||||
expect(a_request(:get, 'http://example.com')).to have_been_made.once
|
expect(a_request(:get, 'http://example.com')).to have_been_made.once
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'executes a HTTP request when the first address is private' do
|
||||||
|
allow(Addrinfo).to receive(:foreach).with('example.com', nil, nil, :SOCK_STREAM)
|
||||||
|
.and_yield(Addrinfo.new(["AF_INET", 0, "example.com", "0.0.0.0"], :PF_INET, :SOCK_STREAM))
|
||||||
|
.and_yield(Addrinfo.new(["AF_INET6", 0, "example.com", "2001:4860:4860::8844"], :PF_INET6, :SOCK_STREAM))
|
||||||
|
expect(a_request(:get, 'http://example.com')).to have_been_made.once
|
||||||
|
end
|
||||||
|
|
||||||
it 'sets headers' do
|
it 'sets headers' do
|
||||||
expect(a_request(:get, 'http://example.com').with(headers: subject.headers)).to have_been_made
|
expect(a_request(:get, 'http://example.com').with(headers: subject.headers)).to have_been_made
|
||||||
end
|
end
|
||||||
|
@ -61,7 +68,9 @@ describe Request do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises Mastodon::ValidationError' do
|
it 'raises Mastodon::ValidationError' do
|
||||||
allow(IPSocket).to receive(:getaddress).with('example.com').and_return('0.0.0.0')
|
allow(Addrinfo).to receive(:foreach).with('example.com', nil, nil, :SOCK_STREAM)
|
||||||
|
.and_yield(Addrinfo.new(["AF_INET", 0, "example.com", "0.0.0.0"], :PF_INET, :SOCK_STREAM))
|
||||||
|
.and_yield(Addrinfo.new(["AF_INET6", 0, "example.com", "2001:db8::face"], :PF_INET6, :SOCK_STREAM))
|
||||||
expect{ subject.perform }.to raise_error Mastodon::ValidationError
|
expect{ subject.perform }.to raise_error Mastodon::ValidationError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue