Use separate email-friendly token for incoming email and let incoming

email token be reset
This commit is contained in:
Douwe Maan 2016-08-19 18:33:46 -05:00 committed by tiagonbotelho
parent 09f4af04c6
commit 9d51421346
12 changed files with 79 additions and 34 deletions

View File

@ -26,7 +26,15 @@ class ProfilesController < Profiles::ApplicationController
def reset_private_token def reset_private_token
if current_user.reset_authentication_token! if current_user.reset_authentication_token!
flash[:notice] = "Token was successfully updated" flash[:notice] = "Private token was successfully updated"
end
redirect_to profile_account_path
end
def reset_incoming_email_token
if current_user.reset_incoming_email_token!
flash[:notice] = "Incoming email token was successfully updated"
end end
redirect_to profile_account_path redirect_to profile_account_path

View File

@ -4,17 +4,21 @@ module TokenAuthenticatable
private private
def write_new_token(token_field) def write_new_token(token_field)
new_token = generate_token(token_field) new_token = generate_available_token(token_field)
write_attribute(token_field, new_token) write_attribute(token_field, new_token)
end end
def generate_token(token_field) def generate_available_token(token_field)
loop do loop do
token = Devise.friendly_token token = generate_token(token_field)
break token unless self.class.unscoped.find_by(token_field => token) break token unless self.class.unscoped.find_by(token_field => token)
end end
end end
def generate_token(token_field)
Devise.friendly_token
end
class_methods do class_methods do
def authentication_token_fields def authentication_token_fields
@token_fields || [] @token_fields || []

View File

@ -624,13 +624,12 @@ class Project < ActiveRecord::Base
end end
def new_issue_address(author) def new_issue_address(author)
# This feature is disabled for the time being. return unless Gitlab::IncomingEmail.enabled? && author
return nil
author.ensure_incoming_email_token!
if Gitlab::IncomingEmail.enabled? && author # rubocop:disable Lint/UnreachableCode
Gitlab::IncomingEmail.reply_address( Gitlab::IncomingEmail.reply_address(
"#{path_with_namespace}+#{author.authentication_token}") "#{path_with_namespace}+#{author.incoming_email_token}")
end
end end
def build_commit_note(commit) def build_commit_note(commit)

View File

@ -13,6 +13,7 @@ class User < ActiveRecord::Base
DEFAULT_NOTIFICATION_LEVEL = :participating DEFAULT_NOTIFICATION_LEVEL = :participating
add_authentication_token_field :authentication_token add_authentication_token_field :authentication_token
add_authentication_token_field :incoming_email_token
default_value_for :admin, false default_value_for :admin, false
default_value_for(:external) { current_application_settings.user_default_external } default_value_for(:external) { current_application_settings.user_default_external }
@ -119,7 +120,7 @@ class User < ActiveRecord::Base
before_validation :set_public_email, if: ->(user) { user.public_email_changed? } before_validation :set_public_email, if: ->(user) { user.public_email_changed? }
after_update :update_emails_with_primary_email, if: ->(user) { user.email_changed? } after_update :update_emails_with_primary_email, if: ->(user) { user.email_changed? }
before_save :ensure_authentication_token before_save :ensure_authentication_token, :ensure_incoming_email_token
before_save :ensure_external_user_rights before_save :ensure_external_user_rights
after_save :ensure_namespace_correct after_save :ensure_namespace_correct
after_initialize :set_projects_limit after_initialize :set_projects_limit
@ -946,4 +947,13 @@ class User < ActiveRecord::Base
signup_domain =~ regexp signup_domain =~ regexp
end end
end end
def generate_token(token_field)
if token_field == :incoming_email_token
# Needs to be all lowercase and alphanumeric because it's gonna be used in an email address.
SecureRandom.hex
else
super
end
end
end end

View File

@ -8,11 +8,14 @@
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.profile-settings-sidebar .col-lg-3.profile-settings-sidebar
%h4.prepend-top-0 %h4.prepend-top-0
Private Token Private Tokens
%p %p
Your private token is used to access application resources without authentication. Your private token is used to access the API and Atom feeds without
username/password authentication.
%p
Your incoming email token is used to create new issues by email, and is
included in your project-specific email addresses.
.col-lg-9 .col-lg-9
= form_for @user, url: reset_private_token_profile_path, method: :put, html: { class: "private-token" } do |f|
%p.cgray %p.cgray
- if current_user.private_token - if current_user.private_token
= label_tag "token", "Private token", class: "label-light" = label_tag "token", "Private token", class: "label-light"
@ -20,12 +23,14 @@
- else - else
%span You don`t have one yet. Click generate to fix it. %span You don`t have one yet. Click generate to fix it.
%p.help-block %p.help-block
It can be used for atom feeds or the API. Keep it secret! Keep this token secret, anyone with access to it can interact with the GitLab API as if they were you.
.prepend-top-default .prepend-top-default
- if current_user.private_token - if current_user.private_token
= f.submit 'Reset private token', data: { confirm: "Are you sure?" }, class: "btn btn-default" = link_to 'Reset private token', reset_private_token_profile_path, method: :put, data: { confirm: "Are you sure?" }, class: "btn btn-default"
- else - else
= f.submit 'Generate', class: "btn btn-default" = f.submit 'Generate', class: "btn btn-default"
= link_to 'Reset incoming email token', reset_incoming_email_token_profile_path, method: :put, data: { confirm: "Are you sure?" }, class: "btn btn-default"
%hr %hr
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.profile-settings-sidebar .col-lg-3.profile-settings-sidebar

View File

@ -4,6 +4,7 @@ resource :profile, only: [:show, :update] do
get :applications, to: 'oauth/applications#index' get :applications, to: 'oauth/applications#index'
put :reset_private_token put :reset_private_token
put :reset_incoming_email_token
put :update_username put :update_username
end end

View File

@ -0,0 +1,16 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddIncomingEmailTokenToUsers < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def change
add_column :users, :incoming_email_token, :string
add_concurrent_index :users, :incoming_email_token
end
end

View File

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20161103171205) do ActiveRecord::Schema.define(version: 20160819232256) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -1176,6 +1176,7 @@ ActiveRecord::Schema.define(version: 20161103171205) do
t.boolean "ldap_email", default: false, null: false t.boolean "ldap_email", default: false, null: false
t.boolean "external", default: false t.boolean "external", default: false
t.string "organization" t.string "organization"
t.string "incoming_email_token"
end end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
@ -1185,6 +1186,7 @@ ActiveRecord::Schema.define(version: 20161103171205) do
add_index "users", ["current_sign_in_at"], name: "index_users_on_current_sign_in_at", using: :btree add_index "users", ["current_sign_in_at"], name: "index_users_on_current_sign_in_at", using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["email"], name: "index_users_on_email_trigram", using: :gin, opclasses: {"email"=>"gin_trgm_ops"} add_index "users", ["email"], name: "index_users_on_email_trigram", using: :gin, opclasses: {"email"=>"gin_trgm_ops"}
add_index "users", ["incoming_email_token"], name: "index_users_on_incoming_email_token", using: :btree
add_index "users", ["name"], name: "index_users_on_name", using: :btree add_index "users", ["name"], name: "index_users_on_name", using: :btree
add_index "users", ["name"], name: "index_users_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} add_index "users", ["name"], name: "index_users_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree

View File

@ -5,16 +5,16 @@ module Gitlab
module Email module Email
module Handler module Handler
class CreateIssueHandler < BaseHandler class CreateIssueHandler < BaseHandler
attr_reader :project_path, :authentication_token attr_reader :project_path, :incoming_email_token
def initialize(mail, mail_key) def initialize(mail, mail_key)
super(mail, mail_key) super(mail, mail_key)
@project_path, @authentication_token = @project_path, @incoming_email_token =
mail_key && mail_key.split('+', 2) mail_key && mail_key.split('+', 2)
end end
def can_handle? def can_handle?
!authentication_token.nil? !incoming_email_token.nil?
end end
def execute def execute
@ -29,7 +29,7 @@ module Gitlab
end end
def author def author
@author ||= User.find_by(authentication_token: authentication_token) @author ||= User.find_by(incoming_email_token: incoming_email_token)
end end
def project def project

View File

@ -18,7 +18,7 @@ xdescribe Gitlab::Email::Handler::CreateIssueHandler, lib: true do
create( create(
:user, :user,
email: 'jake@adventuretime.ooo', email: 'jake@adventuretime.ooo',
authentication_token: 'auth_token' incoming_email_token: 'auth_token'
) )
end end
@ -60,8 +60,8 @@ xdescribe Gitlab::Email::Handler::CreateIssueHandler, lib: true do
end end
end end
context "when we can't find the authentication_token" do context "when we can't find the incoming_email_token" do
let(:email_raw) { fixture_file("emails/wrong_authentication_token.eml") } let(:email_raw) { fixture_file("emails/wrong_incoming_email_token.eml") }
it "raises an UserNotFoundError" do it "raises an UserNotFoundError" do
expect { receiver.execute }.to raise_error(Gitlab::Email::UserNotFoundError) expect { receiver.execute }.to raise_error(Gitlab::Email::UserNotFoundError)