code-ruby 5.1.0 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/code/object/cryptography.rb +30 -0
- data/lib/code/object/smtp.rb +104 -36
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 978d1a5cd5c7828f25ac0d619f50d68dcee1596a9fd3d92ac4e1ba684bfe2481
|
|
4
|
+
data.tar.gz: 06c6cb5d2bf9e3b596d1524ea710dd3ec7f6c8abcd871f07c62f1eb291967c94
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9c314514dc4d2ca20ebd674fe158b90b1f2200008e9e56389fab38513d8b81a1f21f7bd2dbd85f3bf16fe0d376c6879737524bb7597070a413b767d0b43df5a4
|
|
7
|
+
data.tar.gz: 6ad13fe0f05f93e56fece2befeaf33fb08a10c5f3d2a8186021d57a2e7d6bd7c246615690e78bf950ab25f5453ce9af3b4d43399f6b7e3ea543d7fef83daecf1
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.1
|
|
1
|
+
5.2.1
|
|
@@ -13,7 +13,18 @@ class Code
|
|
|
13
13
|
"Cryptography.sha512(:hello, format: :base64)"
|
|
14
14
|
]
|
|
15
15
|
}.freeze
|
|
16
|
+
HMAC_ALGORITHM = "SHA256"
|
|
17
|
+
DEFAULT_FORMAT = "hex"
|
|
16
18
|
CLASS_FUNCTIONS = {
|
|
19
|
+
"hmac_sha256" => {
|
|
20
|
+
name: "hmac_sha256",
|
|
21
|
+
description: "returns an HMAC SHA256 signature as hex, digest, or base64.",
|
|
22
|
+
examples: [
|
|
23
|
+
'Cryptography.hmac_sha256("key", "hello")',
|
|
24
|
+
'Cryptography.hmac_sha256("key", "hello", format: :base64)',
|
|
25
|
+
'Cryptography.hmac_sha256("key", "hello", format: :digest).size'
|
|
26
|
+
]
|
|
27
|
+
},
|
|
17
28
|
"md5" => {
|
|
18
29
|
name: "md5",
|
|
19
30
|
description:
|
|
@@ -78,6 +89,9 @@ class Code
|
|
|
78
89
|
arguments = code_arguments.raw
|
|
79
90
|
|
|
80
91
|
case code_operator.to_s
|
|
92
|
+
when "hmac_sha256"
|
|
93
|
+
sig(args) { [Object, Object, { format: String.maybe }] }
|
|
94
|
+
code_hmac_sha256(*arguments)
|
|
81
95
|
when "md5"
|
|
82
96
|
sig(args) { [Object, { format: String.maybe }] }
|
|
83
97
|
code_md5(*arguments)
|
|
@@ -98,6 +112,22 @@ class Code
|
|
|
98
112
|
end
|
|
99
113
|
end
|
|
100
114
|
|
|
115
|
+
def self.code_hmac_sha256(key, payload, options = nil)
|
|
116
|
+
code_format = (options || {}).to_code.code_get("format")
|
|
117
|
+
format = code_format.nothing? ? DEFAULT_FORMAT : code_format.to_s.downcase
|
|
118
|
+
digest = OpenSSL::HMAC.digest(HMAC_ALGORITHM, key.to_s, payload.to_s)
|
|
119
|
+
case format
|
|
120
|
+
when "hex", "hexdigest"
|
|
121
|
+
digest.unpack1("H*").to_code
|
|
122
|
+
when "digest"
|
|
123
|
+
digest.to_code
|
|
124
|
+
when "base64"
|
|
125
|
+
::Base64.strict_encode64(digest).to_code
|
|
126
|
+
else
|
|
127
|
+
raise Error, "Cryptography: unknown format #{format.inspect}"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
101
131
|
def self.code_md5(*arguments)
|
|
102
132
|
payload = arguments[0]
|
|
103
133
|
options = arguments[1] || Nothing.new
|
data/lib/code/object/smtp.rb
CHANGED
|
@@ -8,6 +8,38 @@ class Code
|
|
|
8
8
|
description: "stores smtp settings and sends email messages.",
|
|
9
9
|
examples: %w[Smtp Smtp.new Smtp.new.functions.keys.include?(:send)]
|
|
10
10
|
}.freeze
|
|
11
|
+
MESSAGE_ARGUMENTS = {
|
|
12
|
+
from: String.maybe,
|
|
13
|
+
to: String.maybe,
|
|
14
|
+
subject: String.maybe,
|
|
15
|
+
body: String.maybe,
|
|
16
|
+
body_text: String.maybe,
|
|
17
|
+
body_html: String.maybe,
|
|
18
|
+
message_id: String.maybe
|
|
19
|
+
}.freeze
|
|
20
|
+
TEXT_CONTENT_TYPE = "text/plain; charset=UTF-8"
|
|
21
|
+
HTML_CONTENT_TYPE = "text/html; charset=UTF-8"
|
|
22
|
+
MULTIPART_CONTENT_TYPE = "multipart/alternative"
|
|
23
|
+
CLASS_FUNCTIONS = {
|
|
24
|
+
"encode" => {
|
|
25
|
+
name: "encode",
|
|
26
|
+
description: "encodes a message as MIME email.",
|
|
27
|
+
examples: [
|
|
28
|
+
'Smtp.encode({from: "a@example.com", to: "b@example.com", body: "hello"})',
|
|
29
|
+
'Smtp.encode({subject: "hello", body_text: "world"})',
|
|
30
|
+
'Smtp.encode({body_html: "<p>hello</p>"})'
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"address" => {
|
|
34
|
+
name: "address",
|
|
35
|
+
description: "parses a single email address and display name.",
|
|
36
|
+
examples: [
|
|
37
|
+
'Smtp.address("a@example.com")',
|
|
38
|
+
'Smtp.address("Alice <a@example.com>")',
|
|
39
|
+
'Smtp.address("Bob <b@example.com>")'
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}.freeze
|
|
11
43
|
INSTANCE_FUNCTIONS = {
|
|
12
44
|
"send" => {
|
|
13
45
|
name: "send",
|
|
@@ -23,7 +55,7 @@ class Code
|
|
|
23
55
|
def self.function_documentation(scope)
|
|
24
56
|
return INSTANCE_FUNCTIONS if scope == :instance
|
|
25
57
|
|
|
26
|
-
|
|
58
|
+
CLASS_FUNCTIONS
|
|
27
59
|
end
|
|
28
60
|
|
|
29
61
|
DEFAULT_PORT = 587
|
|
@@ -31,6 +63,69 @@ class Code
|
|
|
31
63
|
DEFAULT_DOMAIN = "localhost.localdomain"
|
|
32
64
|
ALLOWED_PORTS = [465, 587].freeze
|
|
33
65
|
|
|
66
|
+
def self.call(**args)
|
|
67
|
+
code_operator = args.fetch(:operator, nil).to_code
|
|
68
|
+
code_arguments = args.fetch(:arguments, []).to_code
|
|
69
|
+
|
|
70
|
+
case code_operator.to_s
|
|
71
|
+
when "encode"
|
|
72
|
+
sig(args) { MESSAGE_ARGUMENTS }
|
|
73
|
+
code_encode(code_arguments.code_first)
|
|
74
|
+
when "address"
|
|
75
|
+
sig(args) { String }
|
|
76
|
+
code_address(*code_arguments.raw)
|
|
77
|
+
else
|
|
78
|
+
super
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def self.code_address(value)
|
|
83
|
+
text = value.to_s
|
|
84
|
+
raise Error, "smtp: invalid address" if text.match?(/[\r\n]/)
|
|
85
|
+
|
|
86
|
+
addresses = Mail::AddressList.new(text).addresses
|
|
87
|
+
raise Error, "smtp: expected one address" unless addresses.length == 1
|
|
88
|
+
|
|
89
|
+
address = addresses.first
|
|
90
|
+
unless address.local.present? && address.domain.present?
|
|
91
|
+
raise Error, "smtp: invalid address"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
{ email: address.address, name: address.display_name }.to_code
|
|
95
|
+
rescue Mail::Field::ParseError
|
|
96
|
+
raise Error, "smtp: invalid address"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.code_encode(message)
|
|
100
|
+
build_mail(message.to_code).encoded.to_code
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.build_mail(message)
|
|
104
|
+
mail = Mail.new
|
|
105
|
+
mail.from = message.code_get("from").to_s
|
|
106
|
+
mail.to = message.code_get("to").to_s
|
|
107
|
+
mail.subject = message.code_get("subject").to_s
|
|
108
|
+
message_id = message.code_get("message_id").to_s
|
|
109
|
+
if message_id.match?(/[\r\n]/)
|
|
110
|
+
raise Error, "smtp: invalid message id"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
mail.message_id = message_id if message_id.present?
|
|
114
|
+
|
|
115
|
+
text_part = Mail::Part.new
|
|
116
|
+
text_part.content_type = TEXT_CONTENT_TYPE
|
|
117
|
+
text_part.body = message.code_get("body_text").to_s.presence || message.code_get("body").to_s
|
|
118
|
+
mail.content_type = MULTIPART_CONTENT_TYPE
|
|
119
|
+
mail.add_part(text_part)
|
|
120
|
+
if message.code_get("body_html").to_s.present?
|
|
121
|
+
html_part = Mail::Part.new
|
|
122
|
+
html_part.content_type = HTML_CONTENT_TYPE
|
|
123
|
+
html_part.body = message.code_get("body_html").to_s
|
|
124
|
+
mail.add_part(html_part)
|
|
125
|
+
end
|
|
126
|
+
mail
|
|
127
|
+
end
|
|
128
|
+
|
|
34
129
|
def call(**args)
|
|
35
130
|
code_operator = args.fetch(:operator, nil).to_code
|
|
36
131
|
code_arguments = args.fetch(:arguments, []).to_code
|
|
@@ -38,16 +133,7 @@ class Code
|
|
|
38
133
|
|
|
39
134
|
case code_operator.to_s
|
|
40
135
|
when "send"
|
|
41
|
-
sig(args)
|
|
42
|
-
{
|
|
43
|
-
from: String.maybe,
|
|
44
|
-
to: String.maybe,
|
|
45
|
-
subject: String.maybe,
|
|
46
|
-
body: String.maybe,
|
|
47
|
-
body_text: String.maybe,
|
|
48
|
-
body_html: String.maybe
|
|
49
|
-
}
|
|
50
|
-
end
|
|
136
|
+
sig(args) { MESSAGE_ARGUMENTS }
|
|
51
137
|
|
|
52
138
|
code_send(
|
|
53
139
|
from: code_value.code_get("from"),
|
|
@@ -55,7 +141,8 @@ class Code
|
|
|
55
141
|
subject: code_value.code_get("subject"),
|
|
56
142
|
body: code_value.code_get("body"),
|
|
57
143
|
body_text: code_value.code_get("body_text"),
|
|
58
|
-
body_html: code_value.code_get("body_html")
|
|
144
|
+
body_html: code_value.code_get("body_html"),
|
|
145
|
+
message_id: code_value.code_get("message_id")
|
|
59
146
|
)
|
|
60
147
|
else
|
|
61
148
|
super
|
|
@@ -68,31 +155,12 @@ class Code
|
|
|
68
155
|
subject: nil,
|
|
69
156
|
body: nil,
|
|
70
157
|
body_text: nil,
|
|
71
|
-
body_html: nil
|
|
158
|
+
body_html: nil,
|
|
159
|
+
message_id: nil
|
|
72
160
|
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
code_body = body.to_code
|
|
77
|
-
code_body_text = body_text.to_code
|
|
78
|
-
code_body_html = body_html.to_code
|
|
79
|
-
|
|
80
|
-
mail = Mail.new
|
|
81
|
-
mail.from = code_from.to_s
|
|
82
|
-
mail.to = code_to.to_s
|
|
83
|
-
mail.subject = code_subject.to_s
|
|
84
|
-
|
|
85
|
-
text_part = Mail::Part.new
|
|
86
|
-
text_part.content_type = "text/plain; charset=UTF-8"
|
|
87
|
-
text_part.body = code_body_text.to_s.presence || code_body.to_s
|
|
88
|
-
|
|
89
|
-
html_part = Mail::Part.new
|
|
90
|
-
html_part.content_type = "text/html; charset=UTF-8"
|
|
91
|
-
html_part.body = code_body_html.to_s
|
|
92
|
-
|
|
93
|
-
mail.content_type = "multipart/alternative"
|
|
94
|
-
mail.add_part(text_part)
|
|
95
|
-
mail.add_part(html_part) if code_body_html.to_s.present?
|
|
161
|
+
mail = self.class.build_mail(
|
|
162
|
+
{ from:, to:, subject:, body:, body_text:, body_html:, message_id: }.to_code
|
|
163
|
+
)
|
|
96
164
|
|
|
97
165
|
address = code_get("address").to_s
|
|
98
166
|
port = code_get("port").nothing? ? DEFAULT_PORT : code_get("port").to_i
|