Skip to content

Commit

Permalink
Generate safe email and domain_name by default (RFC 2606) (#2733)
Browse files Browse the repository at this point in the history
* Generate safe `email` and `domain_name` by default (RFC 2606)

faker-ruby is transitioning to no longer generating potentially
real email and url addresses.

The migration plan is:
First step:
- change `email` and `domain_name` to be RFC 2606 compliant.
 Both now generate safe values by default using the Reserved Top Level
 DNS Names: `example` and `test`.
  To maintain backwards compatibility and give users the option to
  use non-safe domains at their own risk, custom domains are allowed.
  Documentation and tests have been updated.
- add deprecation message for `free_email` and `safe_email` to use
`email` instead.

Second step:
- remove deprecated generators and locales.

Co-authored-by: Thiago Araujo <thd.araujo@gmail.com>

* Disable Rubocop Style/IfUnlessModifier globally

---------

Co-authored-by: Thiago Araujo <thd.araujo@gmail.com>
  • Loading branch information
stefannibrasil and thdaraujo committed Apr 5, 2023
1 parent 03c099a commit 82d7a86
Show file tree
Hide file tree
Showing 34 changed files with 285 additions and 110 deletions.
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,7 @@ Security/Eval:
Description: The use of eval represents a serious security risk.
Exclude:
- 'lib/faker/default/json.rb'

Style/IfUnlessModifier:
Description: Checks for `if` and `unless` statements that would fit on one line if written as modifier `if`/`unless`. The cop also checks for modifier `if`/`unless` lines that exceed the maximum line length.
Enabled: false
43 changes: 32 additions & 11 deletions doc/default/internet.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
# Faker::Internet

### About faker-ruby transition to be RFC 2606 compliant

faker-ruby is transitioning to no longer generating real email and url addresses.

The migration plan is:
- First step:
- change `email` and `domain_name` to be RFC 2606 compliant. Both now generate safe values by default using the Reserved Top Level DNS Names: `example` and `test`. To maintain backwards compatibility and give users the option to use non-safe domains at their own risk, custom domains are allowed.
- add deprecation message for `free_email` and `safe_email` users to switch to `email` instead.
- Second step (after October 2023):
- remove deprecated generators and locales.

To give users time, once the first step is released, users will have until October 2023 to make the necessary changes.

```ruby
# Keyword arguments: name, username, email, password, domain_name, user_agent, uuid etc...
Faker::Internet.user #=> { username: 'alexie', email: 'alexie@example.net' }
Faker::Internet.user('username', 'email', 'password') #=> { username: 'alexie', email: 'alexie@example.net', password: 'DtEf9P8wS31iMyC' }
Faker::Internet.user #=> { username: 'alexie', email: 'trudie@grant.test' }
Faker::Internet.user('username', 'email', 'password') #=> { username: 'alexie', email: 'gayle@kohler.test', password: 'DtEf9P8wS31iMyC' }

# Keyword arguments: name, separators
Faker::Internet.email #=> "eliza@mann.net"
Faker::Internet.email(name: 'Nancy') #=> "nancy@terry.biz"
Faker::Internet.email(name: 'Janelle Santiago', separators: '+') #=> "janelle+santiago@becker.com"
Faker::Internet.email(domain: 'example') #=> "alice@example.name"
# Keyword arguments: name, separators, domain
Faker::Internet.email #=> "eliza@mann.test"
Faker::Internet.email(name: 'Nancy') #=> "nancy@terry.test"
Faker::Internet.email(name: 'Janelle Santiago', separators: ['+']) #=> "janelle+santiago@becker.example"
Faker::Internet.email(domain: 'gmail.com') #=> "foo@gmail.com"
Faker::Internet.email(name: 'sam smith', separators: ['-'], domain: 'test') #=> "sam-smith@test.test"

# Keyword arguments: name
Faker::Internet.free_email #=> "freddy@gmail.com"
Expand Down Expand Up @@ -44,13 +58,18 @@ Faker::Internet.password(min_length: 10, max_length: 20, mix_case: true) #=> "3k
Faker::Internet.password(min_length: 10, max_length: 20, mix_case: true, special_characters: true) #=> "*%NkOnJsH4"

# Keyword arguments: subdomain, domain
Faker::Internet.domain_name #=> "effertz.info"
Faker::Internet.domain_name(domain: "example") #=> "example.net"
Faker::Internet.domain_name(subdomain: true, domain: "example") #=> "horse.example.org"
Faker::Internet.domain_name #=> "herzog.example"
Faker::Internet.domain_name(subdomain: true) #=> "tillman.kohler.test"
Faker::Internet.domain_name(subdomain: true, domain: 'faker') #=> "ebert.faker.example"
Faker::Internet.domain_name(domain: 'faker-ruby.org') #=> "faker-ruby.org"
Faker::Internet.domain_name(subdomain: true, domain: 'faker-ruby.org') #=> "foo.faker-ruby.org"
Faker::Internet.domain_name(subdomain: true, domain: 'faker.faker-ruby.org') #=> "faker.faker-ruby.org"

Faker::Internet.domain_word #=> "haleyziemann"

# Keyword arguments: safe ('example' and 'test' suffixes)
Faker::Internet.domain_suffix #=> "info"
Faker::Internet.domain_suffix(safe: true) #=> "example"

Faker::Internet.ip_v4_address #=> "24.29.18.175"

Expand All @@ -71,7 +90,9 @@ Faker::Internet.mac_address #=> "e6:0d:00:11:ed:4f"
Faker::Internet.mac_address(prefix: '55:44:33') #=> "55:44:33:02:1d:9b"

# Keyword arguments: host, path, scheme
Faker::Internet.url #=> "http://thiel.com/chauncey_simonis"
Faker::Internet.url #=> "http://treutel.test/demarcus"
Faker::Internet.url #=> "http://ullrich.example/fritz_braun"
Faker::Internet.url(host: 'faker') #=> "http://faker/nakita"
Faker::Internet.url(host: 'example.com') #=> "http://example.com/clotilde.swift"
Faker::Internet.url(host: 'example.com', path: '/foobar.html') #=> "http://example.com/foobar.html"

Expand Down
2 changes: 1 addition & 1 deletion doc/default/stripe.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ Use some of the other handy Faker classes for Stripe charge amounts and email.
# Keyword arguments: from, to
Faker::Number.between(from: 3, to: 10) #=> 100

Faker::Internet.free_email #=> "freddy@gmail.com"
Faker::Internet.email #=> "niesha@swaniawski-lynch.test"
```
70 changes: 48 additions & 22 deletions lib/faker/default/internet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class Internet < Base
].each(&:freeze).freeze

class << self
extend Gem::Deprecate

##
# Returns the email address
#
Expand All @@ -25,10 +27,11 @@ class << self
# @param domain [String]
#
# @example
# Faker::Internet.email #=> "samsmith@faker.com"
# Faker::Internet.email(name: 'smith') #=> "smith@faker.com"
# Faker::Internet.email(name: 'sam smith', separators: ['-']) #=> "sam-smith@faker.com"
# Faker::Internet.email(name: 'sam smith', separators: ['-'], domain: 'gmail') #=> "sam-smith@gmail.com"
# Faker::Internet.email #=> "renee@zieme.test"
# Faker::Internet.email(name: 'smith') #=> "smith@bergnaum.test"
# Faker::Internet.email(name: 'sam smith', separators: ['-']) #=> "smith-sam@tromp.example"
# Faker::Internet.email(name: 'sam smith', separators: ['-'], domain: 'test') #=> "sam-smith@test.example"
# Faker::Internet.email(domain: 'gmail.com') #=> "foo@gmail.com"
def email(name: nil, separators: nil, domain: nil)
local_part = if separators
username(specifier: name, separators: separators)
Expand All @@ -37,7 +40,14 @@ def email(name: nil, separators: nil, domain: nil)
end

sanitized_local_part = sanitize_email_local_part(local_part)
construct_email(sanitized_local_part, domain_name(domain: domain))

generate_domain = if domain.nil?
domain_name
else
domain_name(domain: domain)
end

construct_email(sanitized_local_part, generate_domain)
end

##
Expand All @@ -56,6 +66,7 @@ def free_email(name: nil)
fetch('internet.free_email')
)
end
deprecate :free_email, :email, 2023, 10

##
# Returns the email address with fixed domain name as 'example'
Expand All @@ -73,6 +84,7 @@ def safe_email(name: nil)
"example.#{sample(%w[org com net])}"
)
end
deprecate :safe_email, :email, 2023, 10

##
# Returns the username
Expand Down Expand Up @@ -204,23 +216,31 @@ def password(min_length: 8, max_length: 16, mix_case: true, special_characters:
# @param domain [String]
#
# @example
# Faker::Internet.domain_name #=> "test.net"
# Faker::Internet.domain_name(subdomain: true) #=> "test.faker.io"
# Faker::Internet.domain_name(subdomain: true, domain: 'example') #=> "faker.example.com"
# Faker::Internet.domain_name(domain: 'faker') #=> "faker.org"
# Faker::Internet.domain_name #=> "altenwerth-gerhold.example"
# Faker::Internet.domain_name(subdomain: true) #=> "metz.mclaughlin-brekke.test"
# Faker::Internet.domain_name(subdomain: true, domain: 'faker') #=> "foo.faker.test"
# Faker::Internet.domain_name(domain: 'faker-ruby.org') #=> "faker-ruby.org"
# Faker::Internet.domain_name(subdomain: true, domain: 'faker-ruby.org') #=> "foo.faker-ruby.org"
# Faker::Internet.domain_name(subdomain: true, domain: 'faker.faker-ruby.org') #=> "faker.faker-ruby.org"
def domain_name(subdomain: false, domain: nil)
with_locale(:en) do
if domain
domain
.split('.')
.map { |domain_part| Char.prepare(domain_part) }
.tap do |domain_elements|
domain_elements << domain_suffix if domain_elements.length < 2
domain_elements.unshift(Char.prepare(domain_word)) if subdomain && domain_elements.length < 3
if domain_elements.length < 2
domain_elements << domain_suffix(safe: true)
end
if subdomain && domain_elements.length < 3
domain_elements.unshift(Char.prepare(domain_word))
end
end.join('.')
else
[domain_word, domain_suffix].tap do |domain_elements|
domain_elements.unshift(Char.prepare(domain_word)) if subdomain
[domain_word, domain_suffix(safe: true)].tap do |domain_elements|
if subdomain
domain_elements.unshift(Char.prepare(domain_word))
end
end.join('.')
end
end
Expand Down Expand Up @@ -257,10 +277,16 @@ def domain_word
# @return [String]
#
# @example
# Faker::Internet.domain_suffix #=> "com"
# Faker::Internet.domain_suffix #=> "biz"
def domain_suffix
fetch('internet.domain_suffix')
# Faker::Internet.domain_suffix #=> "com"
# Faker::Internet.domain_suffix #=> "biz"
# Faker::Internet.domain_suffix(safe: true) #=> "example"
# Faker::Internet.domain_suffix(safe: true) #=> "test"
def domain_suffix(safe: nil)
if safe
fetch('internet.safe_domain_suffix')
else
fetch('internet.domain_suffix')
end
end

##
Expand Down Expand Up @@ -425,10 +451,10 @@ def ip_v6_cidr
# @param scheme [String]
#
# @example
# Faker::Internet.url #=> "http://sipes-okon.com/hung.macejkovic"
# Faker::Internet.url #=> "http://treutel.test/demarcus"
# Faker::Internet.url(host: 'faker') #=> "http://faker/shad"
# Faker::Internet.url(host: 'faker', path: '/fake_test_path') #=> "http://faker/fake_test_path"
# Faker::Internet.url(host: 'faker', path: '/fake_test_path', scheme: 'https') #=> "https://faker/fake_test_path"
# Faker::Internet.url(host: 'faker', path: '/docs') #=> "http://faker/docs"
# Faker::Internet.url(host: 'faker', path: '/docs', scheme: 'https') #=> "https://faker/docs"
def url(host: domain_name, path: "/#{username}", scheme: 'http')
"#{scheme}://#{host}#{path}"
end
Expand Down Expand Up @@ -546,10 +572,10 @@ def base64(length: 16, padding: false, urlsafe: true)
##
# Produces a randomized hash of internet user details
# @example
# Faker::Internet.user #=> { username: 'alexie', email: 'alexie@example.net' }
# Faker::Internet.user #=> { username: 'alexie', email: 'trudie@grant.test' }
#
# @example
# Faker::Internet.user('username', 'email', 'password') #=> { username: 'alexie', email: 'alexie@example.net', password: 'DtEf9P8wS31iMyC' }
# Faker::Internet.user('username', 'email', 'password') #=> { username: 'alexie', email: 'gayle@kohler.test', password: 'DtEf9P8wS31iMyC' }
#
# @return [hash]
#
Expand Down
2 changes: 1 addition & 1 deletion lib/faker/default/omniauth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def initialize(name: nil, email: nil)
super()

@name = name || "#{Name.first_name} #{Name.last_name}"
@email = email || Internet.safe_email(name: self.name)
@email = email || Internet.email(name: self.name)
@first_name, @last_name = self.name.split
end

Expand Down
2 changes: 1 addition & 1 deletion lib/faker/default/twitter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def user(include_status: true, include_email: false)
verified: Faker::Boolean.boolean(true_ratio: 0.1)
}
user[:status] = Faker::Twitter.status(include_user: false) if include_status
user[:email] = Faker::Internet.safe_email if include_email
user[:email] = Faker::Internet.email if include_email
user
end

Expand Down
3 changes: 3 additions & 0 deletions lib/locales/en/internet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ en:
- org
- io
- co
safe_domain_suffix:
- example
- test
free_email:
- gmail.com
- yahoo.com
Expand Down
Loading

0 comments on commit 82d7a86

Please sign in to comment.