ronin 1.3.0 → 1.4.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog.md +51 -1
- data/Gemfile +1 -1
- data/README.md +36 -41
- data/bin/ronin-install +25 -0
- data/bin/ronin-uninstall +25 -0
- data/bin/ronin-update +25 -0
- data/gemspec.yml +4 -4
- data/lib/bond/completions/ronin.rb +6 -5
- data/lib/ronin/address.rb +0 -2
- data/lib/ronin/auto_load.rb +4 -5
- data/lib/ronin/campaign.rb +1 -0
- data/lib/ronin/credential.rb +6 -5
- data/lib/ronin/database/database.rb +1 -0
- data/lib/ronin/email_address.rb +28 -3
- data/lib/ronin/environment.rb +3 -6
- data/lib/ronin/host_name.rb +1 -3
- data/lib/ronin/host_name_ip_address.rb +0 -2
- data/lib/ronin/ip_address.rb +1 -4
- data/lib/ronin/ip_address_mac_address.rb +0 -2
- data/lib/ronin/mac_address.rb +0 -2
- data/lib/ronin/model/has_unique_name.rb +17 -0
- data/lib/ronin/open_port.rb +0 -4
- data/lib/ronin/organization.rb +0 -1
- data/lib/ronin/os.rb +0 -2
- data/lib/ronin/os_guess.rb +0 -2
- data/lib/ronin/password.rb +17 -1
- data/lib/ronin/port.rb +34 -1
- data/lib/ronin/repository.rb +31 -25
- data/lib/ronin/script/buildable.rb +19 -4
- data/lib/ronin/script/deployable.rb +7 -8
- data/lib/ronin/script/exceptions.rb +1 -0
- data/lib/ronin/script/exceptions/build_failed.rb +27 -0
- data/lib/ronin/script/path.rb +28 -11
- data/lib/ronin/script/script.rb +17 -14
- data/lib/ronin/script/testable.rb +3 -3
- data/lib/ronin/service.rb +0 -1
- data/lib/ronin/service_credential.rb +0 -1
- data/lib/ronin/software.rb +0 -1
- data/lib/ronin/target.rb +0 -2
- data/lib/ronin/tcp_port.rb +0 -1
- data/lib/ronin/ui/cli/class_command.rb +130 -0
- data/lib/ronin/ui/cli/command.rb +344 -159
- data/lib/ronin/ui/cli/commands/campaigns.rb +39 -29
- data/lib/ronin/ui/cli/commands/console.rb +24 -15
- data/lib/ronin/ui/cli/commands/creds.rb +14 -12
- data/lib/ronin/ui/cli/commands/database.rb +63 -46
- data/lib/ronin/ui/cli/commands/emails.rb +15 -15
- data/lib/ronin/ui/cli/commands/help.rb +6 -5
- data/lib/ronin/ui/cli/commands/hosts.rb +24 -24
- data/lib/ronin/ui/cli/commands/install.rb +104 -0
- data/lib/ronin/ui/cli/commands/ips.rb +23 -23
- data/lib/ronin/ui/cli/commands/repos.rb +69 -182
- data/lib/ronin/ui/cli/commands/uninstall.rb +65 -0
- data/lib/ronin/ui/cli/commands/update.rb +100 -0
- data/lib/ronin/ui/cli/commands/urls.rb +24 -24
- data/lib/ronin/ui/cli/model_command.rb +8 -6
- data/lib/ronin/ui/cli/printing.rb +167 -0
- data/lib/ronin/ui/cli/resources_command.rb +21 -13
- data/lib/ronin/ui/cli/script_command.rb +126 -24
- data/lib/ronin/ui/console/commands.rb +4 -1
- data/lib/ronin/ui/console/console.rb +1 -1
- data/lib/ronin/ui/console/context.rb +1 -1
- data/lib/ronin/url.rb +24 -5
- data/lib/ronin/url_query_param.rb +0 -1
- data/lib/ronin/version.rb +1 -1
- data/lib/ronin/web_credential.rb +0 -5
- data/spec/email_address_spec.rb +17 -0
- data/spec/installation_spec.rb +24 -34
- data/spec/model/has_authors_spec.rb +1 -1
- data/spec/model/has_description_spec.rb +1 -1
- data/spec/model/has_license_spec.rb +1 -1
- data/spec/model/has_name_spec.rb +1 -1
- data/spec/model/has_title_spec.rb +1 -1
- data/spec/model/has_version_spec.rb +1 -1
- data/spec/model/model_spec.rb +1 -1
- data/spec/repository_spec.rb +9 -9
- data/spec/script/script_spec.rb +2 -4
- data/spec/spec_helper.rb +16 -0
- data/spec/ui/cli/classes/test_command.rb +7 -3
- data/spec/ui/cli/command_spec.rb +37 -5
- metadata +82 -73
- data/spec/model/spec_helper.rb +0 -20
data/ChangeLog.md
CHANGED
@@ -1,3 +1,53 @@
|
|
1
|
+
### 1.4.0 / 2012-01-01
|
2
|
+
|
3
|
+
* Require open_namespace ~> 0.4.
|
4
|
+
* Require parameters ~> 0.4.
|
5
|
+
* Require uri-query_params ~> 0.6.
|
6
|
+
* Require ronin-support ~> 0.4.
|
7
|
+
* Added {Ronin::Port.parse}.
|
8
|
+
* Added {Ronin::Port.from}.
|
9
|
+
* Added {Ronin::EmailAddress.from}.
|
10
|
+
* Added {Ronin::Password.parse}.
|
11
|
+
* Added {Ronin::Model::HasUniqueName::ClassMethods#parse}.
|
12
|
+
* Added {Ronin::Script::ClassMethods#short_name}.
|
13
|
+
* Added {Ronin::Script::Buildable#build_failed!}.
|
14
|
+
* Added {Ronin::Script::Path#clean}.
|
15
|
+
* Added {Ronin::Script::Path#destroy!}.
|
16
|
+
* Added {Ronin::UI::CLI::Printing}.
|
17
|
+
* Added {Ronin::UI::CLI::ClassCommand}.
|
18
|
+
* Added {Ronin::UI::CLI::ScriptCommand#setup}.
|
19
|
+
* Re-added the `ronin install` command.
|
20
|
+
* Re-added the `ronin uninstall` command.
|
21
|
+
* Re-added the `ronin update` command.
|
22
|
+
* Renamed `Ronin::URL.query_param` to {Ronin::URL.with_query_param}.
|
23
|
+
* Renamed `Ronin::URL.query_value` to {Ronin::URL.with_query_value}.
|
24
|
+
* Renamed `Ronin::Repository.add!` to {Ronin::Repository.add}.
|
25
|
+
* Renamed `Ronin::Repository.install!` to {Ronin::Repository.install}.
|
26
|
+
* Renamed `Ronin::Repository.uninstall!` to {Ronin::Repository.uninstall}.
|
27
|
+
* Renamed `Ronin::UI::CLI::ScriptCommand#load_script` to
|
28
|
+
{Ronin::UI::CLI::ScriptCommand#load!}.
|
29
|
+
* Removed `Ronin::Script::InstanceMethods#script_type` in favor of
|
30
|
+
{Ronin::Script::ClassMethods#short_name}.
|
31
|
+
* Have {Ronin::AutoLoad} call `finalize` directly on the newly auto-loaded
|
32
|
+
model.
|
33
|
+
* Associate {Ronin::EmailAddress} with {Ronin::Credential}.
|
34
|
+
* Ensure that all {Ronin::Script}s have unique name/version properties.
|
35
|
+
* Refactored {Ronin::UI::CLI::Command} to use
|
36
|
+
[Parameters::Options](http://rubydoc.info/gems/parameters/0.4.0/Parameters/Options)
|
37
|
+
from parameters 0.4.0.
|
38
|
+
* {Ronin::UI::CLI::Command#start} now rescues and prints exceptions, then
|
39
|
+
exits with status `-1`.
|
40
|
+
* {Ronin::UI::CLI::ScriptCommand} may now accept additional options for the
|
41
|
+
loaded script after `--`:
|
42
|
+
|
43
|
+
ronin exploit -f myexploit.rb -- --host victim.com --port 1337
|
44
|
+
|
45
|
+
* Fixed a typo in the `ronin repos` command.
|
46
|
+
* The `ronin repos` command now only lists installed Repositories.
|
47
|
+
* `Ronin::Support` is now included into {Ronin}, making all support methods
|
48
|
+
accessible in the `ronin` console.
|
49
|
+
* Allow `ronin` console commands to be prefixed with a `.`.
|
50
|
+
|
1
51
|
### 1.3.0 / 2011-10-16
|
2
52
|
|
3
53
|
* Require DataMapper ~> 1.2.
|
@@ -70,7 +120,7 @@
|
|
70
120
|
* Renamed `Ronin::Engine` to {Ronin::Script}.
|
71
121
|
* Renamed `Ronin::Engine::Verifiable` to {Ronin::Script::Testable}.
|
72
122
|
* Renamed `Ronin::Engine#engine_name` to
|
73
|
-
|
123
|
+
`Ronin::Script::InstanceMethods#script_type`.
|
74
124
|
* Renamed `Ronin::Engine::InstanceMethods#load_original!` to
|
75
125
|
{Ronin::Script::InstanceMethods#load_script!}.
|
76
126
|
* Renamed `Ronin::CachedFile` to {Ronin::Script::Path}.
|
data/Gemfile
CHANGED
@@ -22,7 +22,7 @@ gemspec
|
|
22
22
|
# gem 'dm-timestamps', DM_VERSION, :git => "#{DM_URI}/dm-timestamps.git"
|
23
23
|
|
24
24
|
# Library dependencies
|
25
|
-
# gem 'ronin-support', '~> 0.
|
25
|
+
# gem 'ronin-support', '~> 0.4.0.rc1', :git => "#{RONIN_URI}/ronin-support.git"
|
26
26
|
|
27
27
|
group :development do
|
28
28
|
gem 'rake', '~> 0.8'
|
data/README.md
CHANGED
@@ -13,24 +13,35 @@ Ronin is a Ruby platform for exploit development and security research.
|
|
13
13
|
Ronin allows for the rapid development and distribution of code, exploits
|
14
14
|
or payloads over many common Source-Code-Management (SCM) systems.
|
15
15
|
|
16
|
-
###
|
16
|
+
### Customized Console
|
17
17
|
|
18
|
-
Ronin
|
19
|
-
|
18
|
+
Ronin provides users with a customized Ruby Console, pre-loaded with powerful
|
19
|
+
convenience methods. In the Console one can work with data and automate
|
20
|
+
complex tasks, with greater ease than the command-line.
|
20
21
|
|
21
|
-
|
22
|
+
>> File.read('data').base64_decode
|
22
23
|
|
23
|
-
|
24
|
-
Ruby using [DataMapper](http://datamapper.org). With Ronin, storing or
|
25
|
-
querying IP addresses, Hosts, Ports, URLs, Passwords is as simple as a
|
26
|
-
single line of Ruby.
|
24
|
+
### Integrated Database
|
27
25
|
|
28
|
-
|
26
|
+
Ronin ships with a preconfigured Database, that one can interact with from Ruby,
|
27
|
+
without having to write any SQL.
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
>> HostName.tld('eu').urls.with_query_param('id')
|
30
|
+
|
31
|
+
### Repositories
|
32
|
+
|
33
|
+
Ronin supports a Repository system, allowing users to organize and share
|
34
|
+
miscallaneous Data, Code, Exploits, Payloads, Scanners, etc.
|
35
|
+
|
36
|
+
$ ronin install git://github.com/user/exploits.git
|
37
|
+
|
38
|
+
### Libraries
|
39
|
+
|
40
|
+
Ronin provides libraries with additional functionality, such as
|
41
|
+
[Exploitation](http://github.com/ronin-ruby/ronin-exploits#readme)
|
42
|
+
and [Scanning](http://github.com/ronin-ruby/ronin-scanners#readme).
|
43
|
+
|
44
|
+
$ gem install ronin-exploits
|
34
45
|
|
35
46
|
## Features
|
36
47
|
|
@@ -148,13 +159,15 @@ Remove a Database:
|
|
148
159
|
* [dm-is-predefined](http://github.com/postmodern/dm-is-predefined#readme)
|
149
160
|
~> 0.4
|
150
161
|
* [uri-query_params](http://github.com/postmodern/uri-query_params#readme)
|
151
|
-
~> 0.
|
162
|
+
~> 0.6
|
152
163
|
* [open_namespace](http://github.com/postmodern/open_namespace#readme)
|
153
|
-
~> 0.
|
164
|
+
~> 0.4
|
154
165
|
* [data_paths](http://github.com/postmodern/data_paths#readme)
|
155
166
|
~> 0.3
|
156
167
|
* [object_loader](http://github.com/postmodern/object_loader#readme)
|
157
168
|
~> 1.0
|
169
|
+
* [parameters](http://github.com/postmodern/parameters#readme)
|
170
|
+
~> 0.4
|
158
171
|
* [env](http://github.com/postmodern/env#readme)
|
159
172
|
~> 0.2
|
160
173
|
* [pullr](http://github.com/postmodern/pullr#readme)
|
@@ -169,39 +182,21 @@ Remove a Database:
|
|
169
182
|
~> 0.1
|
170
183
|
* [ripl-color_result](https://github.com/janlelis/ripl-color_result#readme)
|
171
184
|
~> 0.3
|
172
|
-
* [thor](http://github.com/wycats/thor#readme)
|
173
|
-
~> 0.14.3
|
174
185
|
* [ronin-support](http://github.com/ronin-ruby/ronin-support#readme)
|
175
|
-
~> 0.
|
186
|
+
~> 0.4
|
176
187
|
|
177
188
|
## Install
|
178
189
|
|
179
|
-
|
180
|
-
|
181
|
-
## Additional Libraries
|
182
|
-
|
183
|
-
### Ronin Gen
|
184
|
-
|
185
|
-
[Ronin Gen](http://github.com/ronin-ruby/ronin-gen#readme) is a Ruby library
|
186
|
-
for Ronin that provides various generators.
|
190
|
+
### Stable
|
187
191
|
|
188
|
-
|
189
|
-
|
190
|
-
[Ronin Web](http://github.com/ronin-ruby/ronin-web#readme) is a Ruby library
|
191
|
-
for Ronin that provides support for web scraping and spidering
|
192
|
-
functionality.
|
193
|
-
|
194
|
-
### Ronin Exploits
|
195
|
-
|
196
|
-
[Ronin Exploits](http://github.com/ronin-ruby/ronin-exploits#readme) is a
|
197
|
-
Ruby library for Ronin that provides exploitation and payload crafting
|
198
|
-
functionality.
|
192
|
+
$ gem install ronin
|
199
193
|
|
200
|
-
###
|
194
|
+
### Edge
|
201
195
|
|
202
|
-
|
203
|
-
|
204
|
-
|
196
|
+
$ git clone git://github.com/ronin-ruby/ronin.git
|
197
|
+
$ cd ronin/
|
198
|
+
$ bundle install
|
199
|
+
$ ./bin/ronin
|
205
200
|
|
206
201
|
## License
|
207
202
|
|
data/bin/ronin-install
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
|
6
|
+
if File.directory?(File.join(root_dir,'.git'))
|
7
|
+
Dir.chdir(root_dir) do |path|
|
8
|
+
require 'bundler'
|
9
|
+
|
10
|
+
begin
|
11
|
+
Bundler.setup(:default)
|
12
|
+
rescue Bundler::BundlerError => e
|
13
|
+
warn e.message
|
14
|
+
warn "Run `bundle install` to install missing gems"
|
15
|
+
exit e.status_code
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
lib_dir = File.join(root_dir,'lib')
|
21
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
22
|
+
|
23
|
+
require 'ronin/ui/cli/commands/install'
|
24
|
+
|
25
|
+
Ronin::UI::CLI::Commands::Install.start
|
data/bin/ronin-uninstall
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
|
6
|
+
if File.directory?(File.join(root_dir,'.git'))
|
7
|
+
Dir.chdir(root_dir) do |path|
|
8
|
+
require 'bundler'
|
9
|
+
|
10
|
+
begin
|
11
|
+
Bundler.setup(:default)
|
12
|
+
rescue Bundler::BundlerError => e
|
13
|
+
warn e.message
|
14
|
+
warn "Run `bundle install` to install missing gems"
|
15
|
+
exit e.status_code
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
lib_dir = File.join(root_dir,'lib')
|
21
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
22
|
+
|
23
|
+
require 'ronin/ui/cli/commands/uninstall'
|
24
|
+
|
25
|
+
Ronin::UI::CLI::Commands::Uninstall.start
|
data/bin/ronin-update
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
|
6
|
+
if File.directory?(File.join(root_dir,'.git'))
|
7
|
+
Dir.chdir(root_dir) do |path|
|
8
|
+
require 'bundler'
|
9
|
+
|
10
|
+
begin
|
11
|
+
Bundler.setup(:default)
|
12
|
+
rescue Bundler::BundlerError => e
|
13
|
+
warn e.message
|
14
|
+
warn "Run `bundle install` to install missing gems"
|
15
|
+
exit e.status_code
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
lib_dir = File.join(root_dir,'lib')
|
21
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
22
|
+
|
23
|
+
require 'ronin/ui/cli/commands/update'
|
24
|
+
|
25
|
+
Ronin::UI::CLI::Commands::Update.start
|
data/gemspec.yml
CHANGED
@@ -50,10 +50,11 @@ dependencies:
|
|
50
50
|
# DataMapper plugins:
|
51
51
|
dm-is-predefined: ~> 0.4
|
52
52
|
# Library dependencies:
|
53
|
-
uri-query_params: ~> 0.
|
54
|
-
open_namespace: ~> 0.
|
53
|
+
uri-query_params: ~> 0.6
|
54
|
+
open_namespace: ~> 0.4
|
55
55
|
data_paths: ~> 0.3
|
56
56
|
object_loader: ~> 1.0
|
57
|
+
parameters: ~> 0.4
|
57
58
|
env: ~> 0.2
|
58
59
|
pullr: ~> 0.1, >= 0.1.2
|
59
60
|
ripl: ~> 0.3
|
@@ -61,9 +62,8 @@ dependencies:
|
|
61
62
|
ripl-auto_indent: ~> 0.1
|
62
63
|
ripl-short_errors: ~> 0.1
|
63
64
|
ripl-color_result: ~> 0.3
|
64
|
-
thor: ~> 0.14.3
|
65
65
|
# Ronin dependencies:
|
66
|
-
ronin-support: ~> 0.
|
66
|
+
ronin-support: ~> 0.4.0.rc1
|
67
67
|
|
68
68
|
development_dependencies:
|
69
69
|
bundler: ~> 1.0.10
|
@@ -22,23 +22,24 @@ require 'ronin/ui/console/commands'
|
|
22
22
|
require 'set'
|
23
23
|
require 'env'
|
24
24
|
|
25
|
-
complete(:on =>
|
26
|
-
prefix = cmd[1
|
27
|
-
|
25
|
+
complete(:on => /^[\!\.][a-zA-Z]\w*/) do |cmd|
|
26
|
+
prefix = cmd[0,1]
|
27
|
+
name = cmd[1..-1]
|
28
|
+
glob = "#{name}*"
|
28
29
|
paths = Set[]
|
29
30
|
|
30
31
|
# search through $PATH for similar program names
|
31
32
|
Env.paths.each do |dir|
|
32
33
|
Pathname.glob(dir.join(glob)) do |path|
|
33
34
|
if (path.file? && path.executable?)
|
34
|
-
paths << "
|
35
|
+
paths << "#{prefix}#{path.basename}"
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
40
|
# add the black-listed keywords last
|
40
41
|
Ronin::UI::Console::Commands::BLACKLIST.each do |keyword|
|
41
|
-
paths << "
|
42
|
+
paths << "#{prefix}#{keyword}" if keyword.start_with?(name)
|
42
43
|
end
|
43
44
|
|
44
45
|
paths
|
data/lib/ronin/address.rb
CHANGED
data/lib/ronin/auto_load.rb
CHANGED
@@ -18,6 +18,7 @@
|
|
18
18
|
#
|
19
19
|
|
20
20
|
require 'open_namespace'
|
21
|
+
require 'dm-core'
|
21
22
|
|
22
23
|
module Ronin
|
23
24
|
#
|
@@ -55,11 +56,9 @@ module Ronin
|
|
55
56
|
def const_missing(name)
|
56
57
|
const = super(name)
|
57
58
|
|
58
|
-
if
|
59
|
-
|
60
|
-
|
61
|
-
DataMapper.finalize
|
62
|
-
end
|
59
|
+
# if the loaded Class is a DataMapper Resource, re-finalize
|
60
|
+
if const < DataMapper::Resource
|
61
|
+
const.finalize
|
63
62
|
end
|
64
63
|
|
65
64
|
return const
|
data/lib/ronin/campaign.rb
CHANGED
data/lib/ronin/credential.rb
CHANGED
@@ -18,8 +18,6 @@
|
|
18
18
|
#
|
19
19
|
|
20
20
|
require 'ronin/model'
|
21
|
-
require 'ronin/user_name'
|
22
|
-
require 'ronin/password'
|
23
21
|
|
24
22
|
module Ronin
|
25
23
|
#
|
@@ -32,12 +30,15 @@ module Ronin
|
|
32
30
|
# Primary key of the credential
|
33
31
|
property :id, Serial
|
34
32
|
|
35
|
-
# Password of the credential
|
36
|
-
belongs_to :password
|
37
|
-
|
38
33
|
# User name of the credential
|
39
34
|
belongs_to :user_name
|
40
35
|
|
36
|
+
# The optional email address associated with the Credential
|
37
|
+
belongs_to :email_address, :required => false
|
38
|
+
|
39
|
+
# Password of the credential
|
40
|
+
belongs_to :password
|
41
|
+
|
41
42
|
#
|
42
43
|
# Searches for all credentials for a specific user.
|
43
44
|
#
|
data/lib/ronin/email_address.rb
CHANGED
@@ -23,6 +23,7 @@ require 'ronin/model/importable'
|
|
23
23
|
require 'ronin/user_name'
|
24
24
|
require 'ronin/host_name'
|
25
25
|
|
26
|
+
require 'uri/mailto'
|
26
27
|
require 'dm-timestamps'
|
27
28
|
|
28
29
|
module Ronin
|
@@ -47,7 +48,7 @@ module Ronin
|
|
47
48
|
:model => 'IPAddress'
|
48
49
|
|
49
50
|
# Any web credentials that are associated with the email address.
|
50
|
-
has 0..n, :
|
51
|
+
has 0..n, :credentials
|
51
52
|
|
52
53
|
# Tracks when the email address was created at.
|
53
54
|
timestamps :created_at
|
@@ -153,7 +154,7 @@ module Ronin
|
|
153
154
|
#
|
154
155
|
# @api public
|
155
156
|
#
|
156
|
-
def
|
157
|
+
def self.parse(email)
|
157
158
|
user, host = email.split('@',2)
|
158
159
|
|
159
160
|
user.strip!
|
@@ -168,12 +169,36 @@ module Ronin
|
|
168
169
|
raise("email address #{email.dump} must have a host name")
|
169
170
|
end
|
170
171
|
|
171
|
-
return
|
172
|
+
return first_or_new(
|
172
173
|
:user_name => UserName.first_or_new(:name => user),
|
173
174
|
:host_name => HostName.first_or_new(:address => host)
|
174
175
|
)
|
175
176
|
end
|
176
177
|
|
178
|
+
#
|
179
|
+
# Creates a new Email Address.
|
180
|
+
#
|
181
|
+
# @param [URI::MailTo, #to_s] email
|
182
|
+
# The URI or String to create the Email Address from.
|
183
|
+
#
|
184
|
+
# @return [EmailAddress]
|
185
|
+
# The new Email Address.
|
186
|
+
#
|
187
|
+
# @since 1.4.0
|
188
|
+
#
|
189
|
+
# @api public
|
190
|
+
#
|
191
|
+
def self.from(email)
|
192
|
+
email = case email
|
193
|
+
when URI::MailTo
|
194
|
+
email.to
|
195
|
+
else
|
196
|
+
email.to_s
|
197
|
+
end
|
198
|
+
|
199
|
+
return parse(email)
|
200
|
+
end
|
201
|
+
|
177
202
|
#
|
178
203
|
# The user of the email address.
|
179
204
|
#
|