Merge branch 'next-minor' into develop
This commit is contained in:
commit
314239ff2a
27 changed files with 197 additions and 96 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -11,7 +11,6 @@ app/assets/images/custom/
|
|||
# Configuration files
|
||||
config/diaspora.yml
|
||||
config/initializers/secret_token.rb
|
||||
config/initializers/twofa_encryption_key.rb
|
||||
.bundle
|
||||
vendor/bundle/
|
||||
vendor/cache/
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
## Bug fixes
|
||||
|
||||
## Features
|
||||
* Add line mentioning diaspora\* on the splash page [#7966](https://github.com/diaspora/diaspora/pull/7966)
|
||||
* Improve communication about signing up on closed pods [#7896](https://github.com/diaspora/diaspora/pull/7896)
|
||||
|
||||
# 0.7.11.0
|
||||
|
||||
|
|
@ -27,6 +29,9 @@
|
|||
* Enable paranoid mode for devise [#8003](https://github.com/diaspora/diaspora/pull/8003)
|
||||
* Refactor likes cucumber test [#8002](https://github.com/diaspora/diaspora/pull/8002)
|
||||
|
||||
## Bug fixes
|
||||
* Fix old photos without remote url for export [#8012](https://github.com/diaspora/diaspora/pull/8012)
|
||||
|
||||
## Features
|
||||
* Add a manifest.json file as a first step to make diaspora\* a Progressive Web App [#7998](https://github.com/diaspora/diaspora/pull/7998)
|
||||
* Allow `web+diaspora://` links to link to a profile with only the diaspora ID [#8000](https://github.com/diaspora/diaspora/pull/8000)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,14 @@
|
|||
padding: 15px;
|
||||
}
|
||||
|
||||
.part-of-diaspora {
|
||||
font-style: italic;
|
||||
|
||||
a {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form {
|
||||
fieldset { background: none; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
.page-registrations.action-new,
|
||||
.page-registrations.action-create {
|
||||
.page-registrations {
|
||||
.ball {
|
||||
background: image-url('branding/ball.png') no-repeat;
|
||||
background-size: contain;
|
||||
|
|
@ -12,19 +11,24 @@
|
|||
height: 633px;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
.v-center {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
|
||||
h2 {
|
||||
h1 {
|
||||
font-size: 35px;
|
||||
margin: 12px;
|
||||
text-align: center;
|
||||
margin: 12px 0;
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
max-width: 400px;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.captcha-img {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
# the COPYRIGHT file.
|
||||
|
||||
class RegistrationsController < Devise::RegistrationsController
|
||||
before_action :check_registrations_open_or_valid_invite!
|
||||
before_action :check_registrations_open_or_valid_invite!, except: :registrations_closed
|
||||
|
||||
layout -> { request.format == :mobile ? "application" : "with_header" }
|
||||
layout -> { request.format == :mobile ? "application" : "with_header_with_footer" }
|
||||
|
||||
def create
|
||||
@user = User.build(user_params)
|
||||
|
|
@ -28,13 +28,17 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
end
|
||||
end
|
||||
|
||||
def registrations_closed
|
||||
render "registrations/registrations_closed"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_registrations_open_or_valid_invite!
|
||||
return true if AppConfig.settings.enable_registrations? || invite.try(:can_be_used?)
|
||||
|
||||
flash[:error] = params[:invite] ? t("registrations.invalid_invite") : t("registrations.closed")
|
||||
redirect_to new_user_session_path
|
||||
flash[:error] = t("registrations.invalid_invite") if params[:invite]
|
||||
redirect_to registrations_closed_path
|
||||
end
|
||||
|
||||
def invite
|
||||
|
|
|
|||
|
|
@ -19,11 +19,10 @@ class User < ApplicationRecord
|
|||
scope :halfyear_actives, ->(time = Time.now) { logged_in_since(time - 6.month) }
|
||||
scope :active, -> { joins(:person).where(people: {closed_account: false}) }
|
||||
|
||||
attribute :otp_secret
|
||||
attr_encrypted :otp_secret, if: false, prefix: "plain_"
|
||||
|
||||
devise :two_factor_authenticatable,
|
||||
:two_factor_backupable,
|
||||
otp_secret_encryption_key: AppConfig.twofa_encryption_key,
|
||||
otp_backup_code_length: 16,
|
||||
otp_number_of_backup_codes: 10
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@
|
|||
.row
|
||||
.col-md-8.text-center
|
||||
%h1= t("home.default.headline", pod_name: pod_name)
|
||||
- if pod_name != "diaspora*"
|
||||
%h2.part-of-diaspora
|
||||
!= t("home.default.part_of_diaspora",
|
||||
diaspora_site_link: link_to(t("home.default.diaspora_site_link"), "https://diasporafoundation.org/"))
|
||||
%h2= t("home.default.byline")
|
||||
.col-md-4.login-form
|
||||
= render partial: "sessions/form", locals: {mobile: false, resource: User.new, resource_name: :user}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
%ul.nav.navbar-nav.navbar-right
|
||||
- if AppConfig.settings.enable_registrations? && !current_page?(controller: "/registrations", action: :new)
|
||||
- unless current_page?(controller: "/registrations", action: :new)
|
||||
%li= link_to t("devise.shared.links.sign_up"), new_user_registration_path, class: "login"
|
||||
- unless current_page?(controller: "/sessions", action: :new)
|
||||
%li= link_to t("devise.shared.links.sign_in"), new_user_session_path, class: "login"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
- if mobile
|
||||
%legend
|
||||
= image_tag("branding/logos/header-logo2x.png", height: 40, width: 40)
|
||||
= t("aspects.aspect_stream.make_something")
|
||||
= AppConfig.settings.pod_name
|
||||
|
||||
- if mobile
|
||||
= f.label :email, t("registrations.new.email"), class: "control-label", id: "emailLabel"
|
||||
|
|
|
|||
11
app/views/registrations/_registrations_closed.haml
Normal file
11
app/views/registrations/_registrations_closed.haml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
%h2
|
||||
= t("devise.shared.links.sign_up_closed")
|
||||
|
||||
!= t("registrations.closed.closed_pod",
|
||||
wiki: link_to(t("registrations.closed.another_pod"), "https://diasporafoundation.org/getting_started/sign_up"))
|
||||
|
||||
!= t("registrations.closed.find_pods",
|
||||
poduptime: link_to("Poduptime", "https://podupti.me/"))
|
||||
|
||||
!= t("registrations.closed.other_questions",
|
||||
wiki: link_to("Wiki", "https://wiki.diasporafoundation.org/Choosing_a_pod"))
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
#registration
|
||||
.container
|
||||
.row
|
||||
.col-md-10.offset1
|
||||
.col-md-7.hidden-phone
|
||||
%h1.ball
|
||||
.col-md-5.v-center
|
||||
.content.text-center
|
||||
%h2#pod-name
|
||||
= AppConfig.settings.pod_name
|
||||
.col-sm-6.hidden-xs
|
||||
.ball
|
||||
.col-sm-6.col-xs-12.v-center
|
||||
.content.text-center
|
||||
%h1#pod-name
|
||||
= AppConfig.settings.pod_name
|
||||
|
||||
= render partial: "form", locals: {mobile: false}
|
||||
= render partial: "form", locals: {mobile: false}
|
||||
|
|
|
|||
8
app/views/registrations/registrations_closed.haml
Normal file
8
app/views/registrations/registrations_closed.haml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#registration
|
||||
.container
|
||||
.row
|
||||
.col-sm-6.hidden-xs
|
||||
.ball
|
||||
.col-sm-6.col-xs-12.v-center
|
||||
.content
|
||||
= render partial: "registrations_closed"
|
||||
10
app/views/registrations/registrations_closed.mobile.haml
Normal file
10
app/views/registrations/registrations_closed.mobile.haml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
.stream#main-stream
|
||||
- flash.each do |name, msg|
|
||||
.expose#flash-container
|
||||
.flash-message{class: "message alert alert-#{flash_class name}", role: "alert"}
|
||||
= msg
|
||||
|
||||
.login-form
|
||||
.login-container
|
||||
= render partial: "registrations_closed"
|
||||
|
|
@ -553,6 +553,8 @@ en:
|
|||
home:
|
||||
default:
|
||||
headline: "Welcome to %{pod_name}"
|
||||
part_of_diaspora: "Part of the %{diaspora_site_link}"
|
||||
diaspora_site_link: "diaspora* federated network"
|
||||
byline: "The online social world where you are in control"
|
||||
be_who_you_want_to_be: "Be who you want to be"
|
||||
be_who_you_want_to_be_info: "A lot of networks insist that you use your real identity. Not diaspora*. Here you can choose who you want to be, and share as much or as little about yourself as you want. It really is up to you how you want to interact with other people."
|
||||
|
|
@ -1050,7 +1052,11 @@ en:
|
|||
terms_link: "terms of service"
|
||||
create:
|
||||
success: "You’ve joined diaspora*!"
|
||||
closed: "Signups are closed on this diaspora* pod."
|
||||
closed:
|
||||
closed_pod: "This pod is currently closed to new registrations. However, you can still join the diaspora* network by registering on %{wiki}. Because all pods are interconnected, you will have access to the same content there."
|
||||
another_pod: "another pod"
|
||||
find_pods: "There’s a list of pods you can sign up to at %{poduptime}."
|
||||
other_questions: "If you have any other questions regarding choosing a pod, check out our %{wiki}."
|
||||
invalid_invite: "The invite link you provided is no longer valid!"
|
||||
|
||||
reshares:
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ Rails.application.routes.draw do
|
|||
devise_scope :user do
|
||||
get "/users/sign_up" => "registrations#new", :as => :new_user_registration
|
||||
post "/users" => "registrations#create", :as => :user_registration
|
||||
get "/registrations_closed" => "registrations#registrations_closed", :as => :registrations_closed
|
||||
end
|
||||
|
||||
get "users/invitations" => "invitations#new", :as => "new_user_invitation"
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
class AddDeviseTwoFactorToUsers < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
add_column :users, :encrypted_otp_secret, :string
|
||||
add_column :users, :encrypted_otp_secret_iv, :string
|
||||
add_column :users, :encrypted_otp_secret_salt, :string
|
||||
add_column :users, :consumed_timestep, :integer
|
||||
add_column :users, :otp_required_for_login, :boolean
|
||||
change_table :users, bulk: true do |t|
|
||||
t.string :encrypted_otp_secret
|
||||
t.string :encrypted_otp_secret_iv
|
||||
t.string :encrypted_otp_secret_salt
|
||||
t.integer :consumed_timestep
|
||||
t.boolean :otp_required_for_login
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
11
db/migrate/20190509125709_fix_missing_remote_photo_fields.rb
Normal file
11
db/migrate/20190509125709_fix_missing_remote_photo_fields.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FixMissingRemotePhotoFields < ActiveRecord::Migration[5.1]
|
||||
def up
|
||||
Photo.where(remote_photo_path: nil).each do |photo|
|
||||
photo.write_attribute(:unprocessed_image, photo.read_attribute(:processed_image))
|
||||
photo.update_remote_path
|
||||
photo.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
52
db/migrate/20190511150503_decrypt_two_factor_secret.rb
Normal file
52
db/migrate/20190511150503_decrypt_two_factor_secret.rb
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DecryptTwoFactorSecret < ActiveRecord::Migration[5.1]
|
||||
class User < ApplicationRecord
|
||||
end
|
||||
|
||||
def up
|
||||
add_column :users, :plain_otp_secret, :string
|
||||
|
||||
key = twofa_encryption_key
|
||||
decrypt_existing_secrets(key) if key
|
||||
|
||||
change_table :users, bulk: true do |t|
|
||||
t.remove :encrypted_otp_secret
|
||||
t.remove :encrypted_otp_secret_iv
|
||||
t.remove :encrypted_otp_secret_salt
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
raise ActiveRecord::IrreversibleMigration
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def twofa_encryption_key
|
||||
if AppConfig.heroku?
|
||||
ENV["TWOFA_ENCRYPTION_KEY"]
|
||||
else
|
||||
key_file = File.expand_path("../../config/initializers/twofa_encryption_key.rb", File.dirname(__FILE__))
|
||||
|
||||
if File.exist? key_file
|
||||
require key_file
|
||||
File.delete(key_file)
|
||||
|
||||
return Diaspora::Application.config.twofa_encryption_key
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def decrypt_existing_secrets(key)
|
||||
User.where.not(encrypted_otp_secret: nil).each do |user|
|
||||
user.plain_otp_secret = Encryptor.decrypt(
|
||||
value: user.encrypted_otp_secret.unpack("m").first,
|
||||
key: key,
|
||||
iv: user.encrypted_otp_secret_iv.unpack("m").first,
|
||||
salt: user.encrypted_otp_secret_salt.slice(1..-1).unpack("m").first
|
||||
)
|
||||
user.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -98,11 +98,11 @@ Feature: new user registration
|
|||
Then I should not be able to sign up
|
||||
And I should have a validation error on "user_password, user_password_confirmation"
|
||||
|
||||
Scenario: User signs up with an already existing username and email and then tries to sign in (Issue #6136)
|
||||
Scenario: User signs up with an already existing username and email and then tries to sign in
|
||||
When I log out manually
|
||||
And I go to the new user registration page
|
||||
And I fill in the new user form with an existing email and username
|
||||
And I fill in the new user form
|
||||
And I submit the form
|
||||
Then I should see a flash message indicating failure
|
||||
When I click the sign in button
|
||||
When I follow "Sign in"
|
||||
Then I should not see a flash message indicating failure
|
||||
24
features/desktop/registrations.feature
Normal file
24
features/desktop/registrations.feature
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
@javascript
|
||||
Feature: New user registration
|
||||
In order to use Diaspora*
|
||||
As a desktop user
|
||||
I want to register an account
|
||||
|
||||
Scenario: user signs up and goes to getting started
|
||||
Given I am on the new user registration page
|
||||
When I fill in the new user form
|
||||
And I press "Create account"
|
||||
Then I should be on the getting started page
|
||||
And I should see the 'getting started' contents
|
||||
|
||||
Scenario: registrations are closed, user is informed
|
||||
Given the registrations are closed
|
||||
When I am on the new user registration page
|
||||
Then I should see "Open signups are closed at this time"
|
||||
|
||||
Scenario: User is unable to register even by manually sending the POST request
|
||||
Given I am on the new user registration page
|
||||
When I fill in the new user form
|
||||
Given the registrations are closed
|
||||
When I press "Create account"
|
||||
Then I should see "Open signups are closed at this time"
|
||||
|
|
@ -5,8 +5,7 @@ Feature: New user registration
|
|||
I want to register an account
|
||||
|
||||
Background:
|
||||
Given I am on the login page
|
||||
And I follow "Create account" within "#main-nav"
|
||||
Given I am on the new user registration page
|
||||
|
||||
Scenario: user signs up and goes to getting started
|
||||
When I fill in the new user form
|
||||
|
|
@ -74,3 +74,11 @@ end
|
|||
Then (/^I should see the 'getting started' contents$/) do
|
||||
confirm_getting_started_contents
|
||||
end
|
||||
|
||||
Given /^the registrations are closed$/ do
|
||||
AppConfig.settings.enable_registrations = false
|
||||
end
|
||||
|
||||
When /^I fill in the new user form$/ do
|
||||
fill_in_new_user_form
|
||||
end
|
||||
|
|
|
|||
|
|
@ -218,20 +218,12 @@ When /^I view "([^\"]*)"'s first post$/ do |email|
|
|||
visit post_path(post)
|
||||
end
|
||||
|
||||
When /^I fill in the new user form/ do
|
||||
fill_in_new_user_form
|
||||
end
|
||||
|
||||
And /^I should be able to friend "([^\"]*)"$/ do |email|
|
||||
user = User.find_by_email(email)
|
||||
step 'I should see a ".aspect-dropdown"'
|
||||
step "I should see \"#{user.name}\""
|
||||
end
|
||||
|
||||
When /^I click the sign in button$/ do
|
||||
click_link "Sign in"
|
||||
end
|
||||
|
||||
Given /^I did request my photos$/ do
|
||||
@me.perform_export_photos!
|
||||
end
|
||||
|
|
|
|||
|
|
@ -68,24 +68,6 @@ module Configuration
|
|||
end
|
||||
end
|
||||
|
||||
def twofa_encryption_key
|
||||
if heroku?
|
||||
return ENV["TWOFA_ENCRYPTION_KEY"] if ENV["TWOFA_ENCRYPTION_KEY"]
|
||||
|
||||
warn "FATAL: Running on Heroku with TWOFA_ENCRYPTION_KEY unset"
|
||||
warn " Run heroku config:add TWOFA_ENCRYPTION_KEY=#{SecureRandom.hex(32)}"
|
||||
abort
|
||||
else
|
||||
key_file = File.expand_path(
|
||||
"../config/initializers/twofa_encryption_key.rb",
|
||||
File.dirname(__FILE__)
|
||||
)
|
||||
system "DISABLE_SPRING=1 bin/rake generate:twofa_key" unless File.exist? key_file
|
||||
require key_file
|
||||
Diaspora::Application.config.twofa_encryption_key
|
||||
end
|
||||
end
|
||||
|
||||
def version_string
|
||||
return @version_string unless @version_string.nil?
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
namespace :generate do
|
||||
desc "Generates a key for encrypting 2fa tokens"
|
||||
task :twofa_key do
|
||||
path = Rails.root.join("config", "initializers", "twofa_encryption_key.rb")
|
||||
key = SecureRandom.hex(32)
|
||||
File.open(path, "w") do |f|
|
||||
f.write <<~CONF
|
||||
# frozen_string_literal: true
|
||||
|
||||
# The 2fa encryption key is used to encrypt users' OTP tokens in the database.
|
||||
|
||||
# You can regenerate this key by running `rake generate:twofa_key`
|
||||
|
||||
# If you change this key after a user has set up 2fa
|
||||
# the users' tokens cannot be recovered
|
||||
# and they will not be able to log in again!
|
||||
|
||||
Diaspora::Application.config.twofa_encryption_key = "#{key}"
|
||||
CONF
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -25,16 +25,14 @@ describe RegistrationsController, type: :controller do
|
|||
AppConfig.settings.enable_registrations = false
|
||||
end
|
||||
|
||||
it "redirects #new to the login page" do
|
||||
it "redirects #new to the registrations closed page" do
|
||||
get :new
|
||||
expect(flash[:error]).to eq(I18n.t("registrations.closed"))
|
||||
expect(response).to redirect_to new_user_session_path
|
||||
expect(response).to redirect_to registrations_closed_path
|
||||
end
|
||||
|
||||
it "redirects #create to the login page" do
|
||||
it "redirects #create to the registrations closed page" do
|
||||
post :create, params: valid_params
|
||||
expect(flash[:error]).to eq(I18n.t("registrations.closed"))
|
||||
expect(response).to redirect_to new_user_session_path
|
||||
expect(response).to redirect_to registrations_closed_path
|
||||
end
|
||||
|
||||
it "does not redirect if there is a valid invite token" do
|
||||
|
|
@ -45,7 +43,8 @@ describe RegistrationsController, type: :controller do
|
|||
|
||||
it "does redirect if there is an invalid invite token" do
|
||||
get :new, params: {invite: {token: "fssdfsd"}}
|
||||
expect(response).to redirect_to new_user_session_path
|
||||
expect(flash[:error]).to eq(I18n.t("registrations.invalid_invite"))
|
||||
expect(response).to redirect_to registrations_closed_path
|
||||
end
|
||||
|
||||
it "does redirect if there are no invites available with this code" do
|
||||
|
|
@ -53,7 +52,7 @@ describe RegistrationsController, type: :controller do
|
|||
code.update_attributes(count: 0)
|
||||
|
||||
get :new, params: {invite: {token: code.token}}
|
||||
expect(response).to redirect_to new_user_session_path
|
||||
expect(response).to redirect_to registrations_closed_path
|
||||
end
|
||||
|
||||
it "does redirect when invitations are closed now" do
|
||||
|
|
@ -61,7 +60,7 @@ describe RegistrationsController, type: :controller do
|
|||
AppConfig.settings.invitations.open = false
|
||||
|
||||
get :new, params: {invite: {token: code.token}}
|
||||
expect(response).to redirect_to new_user_session_path
|
||||
expect(response).to redirect_to registrations_closed_path
|
||||
end
|
||||
|
||||
it "does not redirect when the registration is open" do
|
||||
|
|
|
|||
|
|
@ -984,9 +984,7 @@ describe User, :type => :model do
|
|||
exported_at
|
||||
exported_photos_at
|
||||
consumed_timestep
|
||||
encrypted_otp_secret
|
||||
encrypted_otp_secret_iv
|
||||
encrypted_otp_secret_salt
|
||||
plain_otp_secret
|
||||
otp_backup_codes
|
||||
otp_required_for_login
|
||||
otp_secret
|
||||
|
|
|
|||
Loading…
Reference in a new issue