Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1169

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176
8000 Add mailer for WebAuthn credential updates by jenshenny · Pull Request #3695 · rubygems/rubygems.org · GitHub
Nothing Special   »   [go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/mailers/mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,22 @@ def mfa_required_popular_gems_announcement(user_id)
subject: mfa_required_popular_gems_subject(@user.mfa_level)
end

def webauthn_credential_created(webauthn_credential_id)
@webauthn_credential = WebauthnCredential.find(webauthn_credential_id)

mail to: @webauthn_credential.user.email,
subject: I18n.t("mailer.webauthn_credential_created.subject")
end

def webauthn_credential_removed(user_id, nickname, deleted_at)
@user = User.find(user_id)
@nickname = nickname
@deleted_at = deleted_at

mail to: @user.email,
subject: I18n.t("mailer.webauthn_credential_removed.subject")
end

def gem_yanked(yanked_by_user_id, version_id, notified_user_id)
@version = Version.find(version_id)
notified_user = User.find(notified_user_id)
Expand Down
13 changes: 13 additions & 0 deletions app/models/webauthn_credential.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,17 @@ class WebauthnCredential < ApplicationRecord
validates :public_key, presence: true
validates :nickname, presence: true, uniqueness: { scope: :user_id }
validates :sign_count, presence: true, numericality: { greater_than_or_equal_to: 0 }

after_create :send_creation_email
after_destroy :send_deletion_email

private

def send_creation_email
Mailer.webauthn_credential_created(id).deliver_later
end

def send_deletion_email
Mailer.webauthn_credential_removed(user_id, nickname, Time.now.utc).deliver_later
end
end
6 changes: 6 additions & 0 deletions app/views/mailer/_compromised_instructions.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
1. If you suspect your account was compromised:
- Change your password (<%= new_password_url %>)
- Reset your API key (<%= profile_api_keys_url %>)
- Enable multi-factor authentication (<%= edit_settings_url %>)
<%= yield %>
2. Report this incident to RubyGems.org by emailing us at support@rubygems.org.
37 changes: 37 additions & 0 deletions app/views/mailer/webauthn_credential_created.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<% @title = t("mailer.webauthn_credential_created.title") %>
<% @sub_title = t("mailer.webauthn_credential_created.subtitle", handle: @webauthn_credential.user.handle) %>

<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#ffffff">
<tr>
<td class="content-spacing" style="font-size:0pt; line-height:0pt; text-align:left" width="20"></td>
<td>
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="35" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>

<div class="h3-1-center" style="color:#1e1e1e; font-family:Georgia, serif; min-width:auto !important; font-size:20px; line-height:26px;">
<p>
A new security device was added to your account on RubyGems.org.
</p>
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="30" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>
<p>
Name: <strong><%= @webauthn_credential.nickname %></strong>
<br/>
Created at: <strong><%= @webauthn_credential.created_at.to_formatted_s(:rfc822) %></strong>
</p>
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="30" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>

<p>If this device creation is expected, you do not need to take further action.</p>
<p>
<strong>Only if this change to your settings is unexpected</strong>
please take immediate steps to secure your account and gems:
</p>

<%= render "compromised_instructions" %>
</div>

<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="30" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>

<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="35" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>
</td>
<td class="content-spacing" style="font-size:0pt; line-height:0pt; text-align:left" width="20"></td>
</tr>
</table>
11 changes: 11 additions & 0 deletions app/views/mailer/webauthn_credential_created.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<%= t("mailer.webauthn_credential_created.subtitle", handle: @webauthn_credential.user.handle) %>

A new security device was added to your account on RubyGems.org.

Name: <%= @webauthn_credential.nickname %>
Created at: <%= @webauthn_credential.created_at.to_formatted_s(:rfc822) %>

If this device creation is expected, you do not need to take further action.
Only if this is unexpected behavior, please take immediate steps to secure your account and gems:

<%= render "compromised_instructions" %>
37 changes: 37 additions & 0 deletions app/views/mailer/webauthn_credential_removed.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<% @title = t("mailer.webauthn_credential_removed.title") %>
<% @sub_title = t("mailer.webauthn_credential_removed.subtitle", handle: @user.handle) %>

<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#ffffff">
<tr>
<td class="content-spacing" style="font-size:0pt; line-height:0pt; text-align:left" width="20"></td>
<td>
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="35" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>

<div class="h3-1-center" style="color:#1e1e1e; font-family:Georgia, serif; min-width:auto !important; font-size:20px; line-height:26px;">
<p>
A security device was removed from your account on RubyGems.org.
</p>
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="30" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>
<p>
Name: <strong><%= @nickname %></strong>
<br/>
Deleted at: <strong><%= @deleted_at.to_formatted_s(:rfc822) %></strong>
</p>
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="30" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>

<p>If this device deletion was expected, you do not need to take further action.</p>
<p>
<strong>Only if this change to your settings is unexpected</strong>
please take immediate steps to secure your account and gems:
</p>

<%= render "compromised_instructions" %>
</div>

<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="30" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>

<table width="100%" border="0" cellspacing="0" cellpadding="0" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%"><tr><td height="35" class="spacer" style="font-size:0pt; line-height:0pt; text-align:center; width:100%; min-width:100%">&nbsp;</td></tr></table>
</td>
<td class="content-spacing" style="font-size:0pt; line-height:0pt; text-align:left" width="20"></td>
</tr>
</table>
11 changes: 11 additions & 0 deletions app/views/mailer/webauthn_credential_removed.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<%= t("mailer.webauthn_credential_removed.subtitle", handle: @user.handle) %>

A new security device was removed from your account on RubyGems.org.

Name: <%= @nickname %>
Deleted at: <%= @deleted_at.to_formatted_s(:rfc822) %>

If this device deletion was expected, you do not need to take further action.
Only if this is unexpected behavior, please take immediate steps to secure your account and gems:

<%= render "compromised_instructions" %>
8 changes: 8 additions & 0 deletions config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ de:
subject:
title:
subtitle:
webauthn_credential_created:
subject:
title:
subtitle:
webauthn_credential_removed:
subject:
title:
subtitle:
email_reset_update:
subject:
title:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ en:
subject: RubyGems.org API key was reset
title: API KEY RESET
subtitle: Hi %{handle}
webauthn_credential_created:
subject: New security device added on RubyGems.org
title: SECURITY DEVICE ADDED
subtitle: Hi %{handle}!
webauthn_credential_removed:
subject: Security device removed on RubyGems.org
title: SECURITY DEVICE REMOVED
subtitle: Hi %{handle}!
email_reset_update:
subject: You have requested email address update on RubyGems.org
title: EMAIL UPDATE REQUESTED
Expand Down
8 changes: 8 additions & 0 deletions config/locales/es.yml
< 103C7 td class="blob-code blob-code-context js-file-line"> subject:
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,14 @@ es:
title:
subtitle:
webauthn_credential_created:
subject:
title:
subtitle:
webauthn_credential_removed:
subject:
title:
subtitle:
email_reset_update:
subject:
title:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,14 @@ fr:
subject:
title:
subtitle:
webauthn_credential_created:
subject:
title:
subtitle:
webauthn_credential_removed:
subject:
title:
subtitle:
email_reset_update:
subject:
title:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,14 @@ ja:
subject:
title:
subtitle:
webauthn_credential_created:
subject:
title:
subtitle:
webauthn_credential_removed:
subject:
title:
subtitle:
email_reset_update:
subject:
title:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ nl:
subject:
title:
subtitle:
webauthn_credential_created:
subject:
title:
subtitle:
webauthn_credential_removed:
subject:
title:
subtitle:
email_reset_update:
subject:
title:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ pt-BR:
subject:
title:
subtitle:
webauthn_credential_created:
subject:
title:
subtitle:
webauthn_credential_removed:
subject:
title:
subtitle:
email_reset_update:
subject:
title:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ zh-CN:
subject:
title:
subtitle:
webauthn_credential_created:
subject:
title:
subtitle:
webauthn_credential_removed:
subject:
title:
subtitle:
email_reset_update:
subject:
title:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/zh-TW.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ zh-TW:
subject:
title:
subtitle:
webauthn_credential_created:
subject:
title:
subtitle:
webauthn_credential_removed:
subject:
title:
subtitle:
email_reset_update:
subject:
title:
Expand Down
50 changes: 38 additions & 12 deletions test/functional/webauthn_credentials_controller_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require "test_helper"

class WebauthnCredentialsControllerTest < ActionController::TestCase
include ActiveJob::TestHelper

context "#create" do
context "when logged out" do
setup do
Expand Down Expand Up @@ -85,17 +87,20 @@ class WebauthnCredentialsControllerTest < ActionController::TestCase
challenge = JSON.parse(response.body)["challenge"]
origin = "http://localhost:3000"
client = WebAuthn::FakeClient.new(origin, encoding: false)
post(
:callback,
params: {
credentials: WebauthnHelpers.create_result(
client: client,
challenge: challenge
),
webauthn_credential: { nickname: @nickname }
},
format: :json
)

perform_enqueued_jobs only: ActionMailer::MailDeliveryJob do
post(
:callback,
params: {
credentials: WebauthnHelpers.create_result(
client: client,
challenge: challenge
),
webauthn_credential: { nickname: @nickname }
},
format: :json
)
end
end

should redirect_to :edit_settings
Expand All @@ -104,6 +109,15 @@ class WebauthnCredentialsControllerTest < ActionController::TestCase
assert_equal @nickname, @user.webauthn_credentials.last.nickname
assert_equal 1, @user.webauthn_credentials.count
end

should "deliver webauthn credential added email" do
assert_equal 1, ActionMailer::Base.deliveries.size
email = ActionMailer::Base.deliveries.last

assert_equal [@user.email], email.to
assert_equal ["no-reply@mailer.rubygems.org"], email.from
assert_equal "New security device added on RubyGems.org", email.subject
end
end

context "when nickname is not present" do
Expand Down Expand Up @@ -164,7 +178,10 @@ class WebauthnCredentialsControllerTest < ActionController::TestCase
@user = create(:user)
@credential = create(:webauthn_credential, user: @user)
sign_in_as @user
delete :destroy, params: { id: @credential.id }

perform_enqueued_jobs only: ActionMailer::MailDeliveryJob do
delete :destroy, params: { id: @credential.id }
end
end

should "destroy the webauthn credential" do
Expand All @@ -185,6 +202,15 @@ class WebauthnCredentialsControllerTest < ActionController::TestCase
refute_nil flash[:error]
end

should "deliver webauthn credential removed email" do
assert_equal 1, ActionMailer::Base.deliveries.size
email = ActionMailer::Base.deliveries.last

assert_equal [@user.email], email.to
assert_equal ["no-reply@mailer.rubygems.org"], email.from
assert_equal "Security device removed on RubyGems.org", email.subject
end

should redirect_to :edit_settings
end
end
27 changes: 27 additions & 0 deletions test/mailers/previews/mailer_preview.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,31 @@ def webhook_disabled_single_gem

WebHooksMailer.webhook_disabled(web_hook)
end

def webauthn_credential_created
webauthn_credential = WebauthnCredential.last

unless webauthn_credential
user_with_yubikey = User.create_with(
handle: "gem-user-with-yubikey",
password: "super-secret-password",
email_confirmed: true
).find_or_create_by!(email: "gem-user-with-yubikey@example.com")

webauthn_credential = user_with_yubikey.webauthn_credentials.create_with(
external_id: "external-id",
public_key: "public-key",
sign_count: 1
).find_or_create_by!(nickname: "Fake Yubikey")
end

Mailer.webauthn_credential_created(webauthn_credential.id)
end

def webauthn_credential_removed
user_id = User.last.id
webauthn_credential_nickname = "Fake Yubikey"

Mailer.webauthn_credential_removed(user_id, webauthn_credential_nickname, Time.now.utc)
end
end
Loading
0